Merge pull request #1933 from akka/wip-3764-props-docs-∂π

clean up docs and deprecation around how to create Props
This commit is contained in:
Roland Kuhn 2014-01-17 05:57:37 -08:00
commit 453815c073
17 changed files with 99 additions and 244 deletions

View file

@ -22,7 +22,7 @@ public class ActorCreationTest {
}); });
assert false; assert false;
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException e) {
assertEquals("cannot use non-static local Creator to create actors; make it static or top-level", e.getMessage()); assertEquals("cannot use non-static local Creator to create actors; make it static (e.g. local to a static method) or top-level", e.getMessage());
} }
} }

View file

@ -48,14 +48,18 @@ public class JavaAPI {
ActorRef ref = system.actorOf(Props.create(JavaAPITestActor.class)); ActorRef ref = system.actorOf(Props.create(JavaAPITestActor.class));
assertNotNull(ref); assertNotNull(ref);
} }
@Test public static Props mkProps() {
public void mustBeAbleToCreateActorRefFromFactory() { return Props.create(new Creator<Actor>() {
ActorRef ref = system.actorOf(Props.empty().withCreator(new Creator<Actor>() {
public Actor create() { public Actor create() {
return new JavaAPITestActor(); return new JavaAPITestActor();
} }
})); });
}
@Test
public void mustBeAbleToCreateActorRefFromFactory() {
ActorRef ref = system.actorOf(mkProps());
assertNotNull(ref); assertNotNull(ref);
} }

View file

@ -159,7 +159,7 @@ object SupervisorHierarchySpec {
val propsTemplate = Props.empty.withDispatcher("hierarchy") val propsTemplate = Props.empty.withDispatcher("hierarchy")
(1 to kids).map { (id) (1 to kids).map { (id)
val kidSize = if (rest > 0) { rest -= 1; sizes + 1 } else sizes val kidSize = if (rest > 0) { rest -= 1; sizes + 1 } else sizes
val props = propsTemplate.withCreator(new Hierarchy(kidSize, breadth, listener, myLevel + 1, random)) val props = Props(new Hierarchy(kidSize, breadth, listener, myLevel + 1, random)).withDeploy(propsTemplate.deploy)
(context.watch(context.actorOf(props, id.toString)).path, kidSize) (context.watch(context.actorOf(props, id.toString)).path, kidSize)
}(collection.breakOut) }(collection.breakOut)
} else Map() } else Map()

View file

@ -272,11 +272,6 @@ class VerifySerializabilitySpec extends AkkaSpec(SerializationTests.verifySerial
val b = system.actorOf(Props(new FooActor)) val b = system.actorOf(Props(new FooActor))
system stop b system stop b
val c = system.actorOf(Props.empty.withCreator(new UntypedActorFactory {
def create() = new FooUntypedActor
}))
system stop c
intercept[IllegalArgumentException] { intercept[IllegalArgumentException] {
val d = system.actorOf(Props(new NonSerializableActor(system))) val d = system.actorOf(Props(new NonSerializableActor(system)))
} }

View file

@ -310,7 +310,7 @@ private[akka] object ActorCell {
final val emptyActorRefSet: Set[ActorRef] = immutable.HashSet.empty final val emptyActorRefSet: Set[ActorRef] = immutable.HashSet.empty
final val terminatedProps: Props = Props(() throw new IllegalActorStateException("This Actor has been terminated")) final val terminatedProps: Props = Props((throw new IllegalActorStateException("This Actor has been terminated")): Actor)
final val undefinedUid = 0 final val undefinedUid = 0

View file

@ -51,7 +51,7 @@ object Props {
/** /**
* The default Props instance, uses the settings from the Props object starting with default*. * The default Props instance, uses the settings from the Props object starting with default*.
*/ */
final val default = new Props() final val default = Props(defaultDeploy, classOf[CreatorFunctionConsumer], List(defaultCreator))
/** /**
* INTERNAL API * INTERNAL API
@ -87,36 +87,6 @@ object Props {
private def mkProps(classOfActor: Class[_], ctor: () Actor): Props = private def mkProps(classOfActor: Class[_], ctor: () Actor): Props =
Props(classOf[TypedCreatorFunctionConsumer], classOfActor, ctor) Props(classOf[TypedCreatorFunctionConsumer], classOfActor, ctor)
/**
* Returns a Props that has default values except for "creator" which will be a function that creates an instance
* using the supplied thunk.
*/
@deprecated("give class and arguments instead", "2.2")
def apply(creator: Creator[_ <: Actor]): Props = default.withCreator(creator.create)
/**
* The deprecated legacy constructor.
*/
@deprecated("use Props.withDispatcher and friends", "2.2")
def apply(
creator: () Actor = Props.defaultCreator,
dispatcher: String = Deploy.NoDispatcherGiven,
routerConfig: RouterConfig = Props.defaultRoutedProps,
deploy: Deploy = Props.defaultDeploy): Props = {
val d1 = if (dispatcher != Deploy.NoDispatcherGiven) deploy.copy(dispatcher = dispatcher) else deploy
val d2 = if (routerConfig != Props.defaultRoutedProps) d1.copy(routerConfig = routerConfig) else d1
val p = Props(classOf[CreatorFunctionConsumer], creator)
if (d2 != Props.defaultDeploy) p.withDeploy(d2) else p
}
/**
* The deprecated legacy extractor.
*/
@deprecated("use three-argument version", "2.2")
def unapply(p: Props)(dummy: Int = 0): Option[(() Actor, String, RouterConfig, Deploy)] =
Some((p.creator, p.dispatcher, p.routerConfig, p.deploy))
/** /**
* Scala API: create a Props given a class and its constructor arguments. * Scala API: create a Props given a class and its constructor arguments.
*/ */
@ -133,7 +103,7 @@ object Props {
*/ */
def create[T <: Actor](creator: Creator[T]): Props = { def create[T <: Actor](creator: Creator[T]): Props = {
if ((creator.getClass.getEnclosingClass ne null) && (creator.getClass.getModifiers & Modifier.STATIC) == 0) if ((creator.getClass.getEnclosingClass ne null) && (creator.getClass.getModifiers & Modifier.STATIC) == 0)
throw new IllegalArgumentException("cannot use non-static local Creator to create actors; make it static or top-level") throw new IllegalArgumentException("cannot use non-static local Creator to create actors; make it static (e.g. local to a static method) or top-level")
val ac = classOf[Actor] val ac = classOf[Actor]
val actorClass = Reflect.findMarker(creator.getClass, classOf[Creator[_]]) match { val actorClass = Reflect.findMarker(creator.getClass, classOf[Creator[_]]) match {
case t: ParameterizedType case t: ParameterizedType
@ -199,37 +169,6 @@ final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]
// validate producer constructor signature; throws IllegalArgumentException if invalid // validate producer constructor signature; throws IllegalArgumentException if invalid
producer producer
/**
* No-args constructor that sets all the default values.
*
* @deprecated use `Props.create(clazz, args ...)` instead
*/
@deprecated("use Props.create()", "2.2")
def this() = this(Props.defaultDeploy, classOf[CreatorFunctionConsumer], List(Props.defaultCreator))
/**
* Java API: create Props from an [[UntypedActorFactory]]
*
* @deprecated use `Props.create(clazz, args ...)` instead; this method has been
* deprecated because it encourages creating Props which contain
* non-serializable inner classes, making them also
* non-serializable
*/
@deprecated("use Props.create()", "2.2")
def this(factory: UntypedActorFactory) = this(Props.defaultDeploy, classOf[UntypedActorFactoryConsumer], List(factory))
/**
* Java API: create Props from a given [[java.lang.Class]]
*
* @deprecated use Props.create(clazz) instead; deprecated since it duplicates
* another API
*/
@deprecated("use Props.create()", "2.2")
def this(actorClass: Class[_ <: Actor]) = this(Props.defaultDeploy, actorClass, List.empty)
@deprecated("There is no use-case for this method anymore", "2.2")
def creator: () Actor = newActor
/** /**
* Convenience method for extracting the dispatcher information from the * Convenience method for extracting the dispatcher information from the
* contained [[Deploy]] instance. * contained [[Deploy]] instance.
@ -254,36 +193,6 @@ final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]
*/ */
def routerConfig: RouterConfig = deploy.routerConfig def routerConfig: RouterConfig = deploy.routerConfig
/**
* Scala API: Returns a new Props with the specified creator set.
*
* The creator must not return the same instance multiple times.
*/
@deprecated("use Props(...).withDeploy(other.deploy)", "2.2")
def withCreator(c: Actor): Props = copy(clazz = classOf[CreatorFunctionConsumer], args = (() c) :: Nil)
/**
* Java API: Returns a new Props with the specified creator set.
*
* The creator must not return the same instance multiple times.
*
* @deprecated use `Props.create(clazz, args ...)` instead; this method has been
* deprecated because it encourages creating Props which contain
* non-serializable inner classes, making them also
* non-serializable
*/
@deprecated("use Props.create(clazz, args ...).withDeploy(other.deploy) instead", "2.2")
def withCreator(c: Creator[Actor]): Props = copy(clazz = classOf[CreatorConsumer], args = classOf[Actor] :: c :: Nil)
/**
* Returns a new Props with the specified creator set.
*
* @deprecated use Props.create(clazz) instead; deprecated since it duplicates
* another API
*/
@deprecated("use Props.create(clazz, args).withDeploy(other.deploy)", "2.2")
def withCreator(c: Class[_ <: Actor]): Props = copy(clazz = c, args = Nil)
/** /**
* Returns a new Props with the specified dispatcher set. * Returns a new Props with the specified dispatcher set.
*/ */

View file

@ -75,7 +75,7 @@ trait TypedActorFactory {
val proxyVar = new AtomVar[R] //Chicken'n'egg-resolver val proxyVar = new AtomVar[R] //Chicken'n'egg-resolver
val c = props.creator //Cache this to avoid closing over the Props val c = props.creator //Cache this to avoid closing over the Props
val i = props.interfaces //Cache this to avoid closing over the Props val i = props.interfaces //Cache this to avoid closing over the Props
val ap = props.actorProps.withCreator(new TypedActor.TypedActor[R, T](proxyVar, c(), i)) val ap = Props(new TypedActor.TypedActor[R, T](proxyVar, c(), i)).withDeploy(props.actorProps.deploy)
typedActor.createActorRefProxy(props, proxyVar, actorFactory.actorOf(ap)) typedActor.createActorRefProxy(props, proxyVar, actorFactory.actorOf(ap))
} }
@ -86,7 +86,7 @@ trait TypedActorFactory {
val proxyVar = new AtomVar[R] //Chicken'n'egg-resolver val proxyVar = new AtomVar[R] //Chicken'n'egg-resolver
val c = props.creator //Cache this to avoid closing over the Props val c = props.creator //Cache this to avoid closing over the Props
val i = props.interfaces //Cache this to avoid closing over the Props val i = props.interfaces //Cache this to avoid closing over the Props
val ap = props.actorProps.withCreator(new akka.actor.TypedActor.TypedActor[R, T](proxyVar, c(), i)) val ap = Props(new akka.actor.TypedActor.TypedActor[R, T](proxyVar, c(), i)).withDeploy(props.actorProps.deploy)
typedActor.createActorRefProxy(props, proxyVar, actorFactory.actorOf(ap, name)) typedActor.createActorRefProxy(props, proxyVar, actorFactory.actorOf(ap, name))
} }
@ -619,7 +619,7 @@ case class TypedProps[T <: AnyRef] protected[TypedProps] (
def actorProps(): Props = def actorProps(): Props =
if (dispatcher == Props.default.dispatcher) if (dispatcher == Props.default.dispatcher)
Props.default.withDeploy(deploy) Props.default.withDeploy(deploy)
else Props(dispatcher = dispatcher).withDeploy(deploy) else Props.default.withDispatcher(dispatcher).withDeploy(deploy)
} }
/** /**

View file

@ -58,8 +58,11 @@ private[akka] trait Dispatch { this: ActorCell ⇒
case _: ProducesMessageQueue[_] if system.mailboxes.hasRequiredType(actorClass) case _: ProducesMessageQueue[_] if system.mailboxes.hasRequiredType(actorClass)
val req = system.mailboxes.getRequiredType(actorClass) val req = system.mailboxes.getRequiredType(actorClass)
if (req isInstance mbox.messageQueue) Create(None) if (req isInstance mbox.messageQueue) Create(None)
else Create(Some(ActorInitializationException(self, else {
s"Actor [$self] requires mailbox type [$req] got [${mbox.messageQueue.getClass.getName}]"))) val gotType = if (mbox.messageQueue == null) "null" else mbox.messageQueue.getClass.getName
Create(Some(ActorInitializationException(self,
s"Actor [$self] requires mailbox type [$req] got [$gotType]")))
}
case _ Create(None) case _ Create(None)
} }

View file

@ -11,14 +11,17 @@ import static akka.pattern.Patterns.pipe;
import static akka.pattern.Patterns.gracefulStop; import static akka.pattern.Patterns.gracefulStop;
//#import-gracefulStop //#import-gracefulStop
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import akka.testkit.AkkaJUnitActorSystemResource; import akka.testkit.AkkaJUnitActorSystemResource;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
//#import-gracefulStop //#import-gracefulStop
import scala.concurrent.Await; import scala.concurrent.Await;
//#import-ask //#import-ask
@ -119,43 +122,6 @@ public class UntypedActorDocTest {
} }
//#parametric-creator //#parametric-creator
@SuppressWarnings("deprecation")
@Test
public void createPropsDeprecated() {
//#creating-props-deprecated
// DEPRECATED: encourages to close over enclosing class
final Props props1 = new Props(new UntypedActorFactory() {
private static final long serialVersionUID = 1L;
@Override
public UntypedActor create() throws Exception {
return new MyUntypedActor();
}
});
// DEPRECATED: encourages to close over enclosing class
final Props props2 = new Props().withCreator(new UntypedActorFactory() {
private static final long serialVersionUID = 1L;
@Override
public UntypedActor create() throws Exception {
return new MyUntypedActor();
}
});
// these are DEPRECATED due to duplicate functionality with Props.create()
final Props props3 = new Props(MyUntypedActor.class);
final Props props4 = new Props().withCreator(MyUntypedActor.class);
//#creating-props-deprecated
new JavaTestKit(system) {
{
for (Props props : new Props[] { props1, props2, props3, props4 }) {
final ActorRef a = system.actorOf(props);
a.tell("hello", getRef());
expectMsgEquals("hello");
}
}
};
}
@Test @Test
public void systemActorOf() { public void systemActorOf() {
//#system-actorOf //#system-actorOf
@ -538,8 +504,15 @@ public class UntypedActorDocTest {
* @return a Props for creating this actor, which can then be further configured * @return a Props for creating this actor, which can then be further configured
* (e.g. calling `.withDispatcher()` on it) * (e.g. calling `.withDispatcher()` on it)
*/ */
public static Props props(int magicNumber) { public static Props props(final int magicNumber) {
return Props.create(DemoActor.class, magicNumber); return Props.create(new Creator<DemoActor>() {
private static final long serialVersionUID = 1L;
@Override
public DemoActor create() throws Exception {
return new DemoActor(magicNumber);
}
});
} }
final int magicNumber; final int magicNumber;

View file

@ -65,52 +65,22 @@ example of a parametric factory could be:
.. includecode:: code/docs/actor/UntypedActorDocTest.java#parametric-creator .. includecode:: code/docs/actor/UntypedActorDocTest.java#parametric-creator
Deprecated Variants .. note::
^^^^^^^^^^^^^^^^^^^
Up to Akka 2.1 there were also the following possibilities (which are retained In order for mailbox requirements—like using a deque-based mailbox for actors
for a migration period): using the stash—to be picked up, the actor type needs to be known before
creating it, which is what the :class:`Creator` type argument allows.
.. includecode:: code/docs/actor/UntypedActorDocTest.java#import-untypedActor Therefore make sure to use the specific type for your actors wherever
.. includecode:: code/docs/actor/UntypedActorDocTest.java#creating-props-deprecated possible.
The last two are deprecated because their functionality is available in full
through :meth:`Props.create()`.
The first two are deprecated because the resulting :class:`UntypedActorFactory`
is typically a local class which means that it implicitly carries a reference
to the enclosing class. This can easily make the resulting :class:`Props`
non-serializable, e.g. when the enclosing class is an :class:`Actor`. Akka
advocates location transparency, meaning that an application written with
actors should just work when it is deployed over multiple network nodes, and
non-serializable actor factories would break this principle. In case indirect
actor creation is needed—for example when using dependency injection—there is
the possibility to use an :class:`IndirectActorProducer` as described below.
There were two use-cases for these methods: passing constructor arguments to
the actor—which is solved by the newly introduced :meth:`Props.create()` method
above—and creating actors “on the spot” as anonymous classes. The latter should
be solved by making these actors named inner classes instead (if they are not
``static`` then the enclosing instances ``this`` reference needs to be passed
as the first argument).
.. warning::
Declaring one actor within another is very dangerous and breaks actor
encapsulation unless the nested actor is a static inner class. Never pass an
actors ``this`` reference into :class:`Props`!
Recommended Practices Recommended Practices
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
It is a good idea to provide static factory methods on the It is a good idea to provide static factory methods on the
:class:`UntypedActor` which help keeping the creation of suitable :class:`UntypedActor` which help keeping the creation of suitable
:class:`Props` as close to the actor definition as possible, thus containing :class:`Props` as close to the actor definition as possible. This also allows
the gap in type-safety introduced by reflective instantiation within a single usage of the :class:`Creator`-based methods which statically verify that the
class instead of spreading it out across a whole code-base. This helps used constructor actually exists instead relying only on a runtime check.
especially when refactoring the actors constructor signature at a later point,
where compiler checks will allow this modification to be done with greater
confidence than without.
.. includecode:: code/docs/actor/UntypedActorDocTest.java#props-factory .. includecode:: code/docs/actor/UntypedActorDocTest.java#props-factory

View file

@ -171,6 +171,7 @@ The following, previously deprecated, features have been removed:
* `event-handlers renamed to loggers <http://doc.akka.io/docs/akka/2.2.3/project/migration-guide-2.1.x-2.2.x.html#event-handlers_renamed_to_loggers>`_ * `event-handlers renamed to loggers <http://doc.akka.io/docs/akka/2.2.3/project/migration-guide-2.1.x-2.2.x.html#event-handlers_renamed_to_loggers>`_
* `API changes to FSM and TestFSMRef <http://doc.akka.io/docs/akka/2.2.3/project/migration-guide-2.1.x-2.2.x.html#API_changes_to_FSM_and_TestFSMRef>`_ * `API changes to FSM and TestFSMRef <http://doc.akka.io/docs/akka/2.2.3/project/migration-guide-2.1.x-2.2.x.html#API_changes_to_FSM_and_TestFSMRef>`_
* DefaultScheduler superseded by LightArrayRevolverScheduler * DefaultScheduler superseded by LightArrayRevolverScheduler
* all previously deprecated construction and deconstruction methods for Props
publishCurrentClusterState is Deprecated publishCurrentClusterState is Deprecated
======================================== ========================================

View file

@ -71,43 +71,37 @@ dispatcher to use, see more below). Here are some examples of how to create a
.. includecode:: code/docs/actor/ActorDocSpec.scala#creating-props .. includecode:: code/docs/actor/ActorDocSpec.scala#creating-props
The last line shows how to pass constructor arguments to the :class:`Actor` The second variant shows how to pass constructor arguments to the
being created. The presence of a matching constructor is verified during :class:`Actor` being created, but it should only be used outside of actors as
construction of the :class:`Props` object, resulting in an explained below.
The last line shows a possibility to pass constructor arguments regardless of
the context it is being used in. The presence of a matching constructor is
verified during construction of the :class:`Props` object, resulting in an
:class:`IllegalArgumentEception` if no or multiple matching constructors are :class:`IllegalArgumentEception` if no or multiple matching constructors are
found. found.
Deprecated Variants Dangerous Variants
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
Up to Akka 2.1 there were also the following possibilities (which are retained
for a migration period):
.. includecode:: code/docs/actor/ActorDocSpec.scala#creating-props-deprecated .. includecode:: code/docs/actor/ActorDocSpec.scala#creating-props-deprecated
The first one is deprecated because the case class structure changed between This method is not recommended to be used within another actor because it
Akka 2.1 and 2.2. encourages to close over the enclosing scope, resulting in non-serializable
The two variants in the middle are deprecated because :class:`Props` are
primarily concerned with actor creation and thus the “creator” part should be
explicitly set when creating an instance. In case you want to deploy one actor
in the same was as another, simply use
``Props(...).withDeploy(otherProps.deploy)``.
The last one is not technically deprecated, but it is not recommended because
it encourages to close over the enclosing scope, resulting in non-serializable
:class:`Props` and possibly race conditions (breaking the actor encapsulation). :class:`Props` and possibly race conditions (breaking the actor encapsulation).
We will provide a macro-based solution in a future release which allows similar We will provide a macro-based solution in a future release which allows similar
syntax without the headaches, at which point this variant will be properly syntax without the headaches, at which point this variant will be properly
deprecated. deprecated. On the other hand using this variant in a :class:`Props` factory in
the actors companion object as documented under “Recommended Practices” below
is completely fine.
There were two use-cases for these methods: passing constructor arguments to There were two use-cases for these methods: passing constructor arguments to
the actor—which is solved by the newly introduced the actor—which is solved by the newly introduced
:meth:`Props.apply(clazz, args)` method above—and creating actors “on the spot” :meth:`Props.apply(clazz, args)` method above or the recommended practice
as anonymous classes. The latter should be solved by making these actors named below—and creating actors “on the spot” as anonymous classes. The latter should
inner classes instead (if they are not declared within a top-level ``object`` be solved by making these actors named classes instead (if they are not
then the enclosing instances ``this`` reference needs to be passed as the declared within a top-level ``object`` then the enclosing instances ``this``
first argument). reference needs to be passed as the first argument).
.. warning:: .. warning::
@ -119,12 +113,10 @@ Recommended Practices
It is a good idea to provide factory methods on the companion object of each It is a good idea to provide factory methods on the companion object of each
:class:`Actor` which help keeping the creation of suitable :class:`Props` as :class:`Actor` which help keeping the creation of suitable :class:`Props` as
close to the actor definition as possible, thus containing the gap in close to the actor definition as possible. This also avoids the pitfalls
type-safety introduced by reflective instantiation within a single class associated with using the ``Props.apply(...)`` method which takes a by-name
instead of spreading it out across a whole code-base. This helps especially argument, since within a companion object the given code block will not retain
when refactoring the actors constructor signature at a later point, where a reference to its enclosing scope:
compiler checks will allow this modification to be done with greater confidence
than without.
.. includecode:: code/docs/actor/ActorDocSpec.scala#props-factory .. includecode:: code/docs/actor/ActorDocSpec.scala#props-factory

View file

@ -59,7 +59,7 @@ class DemoActorWrapper extends Actor {
* @return a Props for creating this actor, which can then be further configured * @return a Props for creating this actor, which can then be further configured
* (e.g. calling `.withDispatcher()` on it) * (e.g. calling `.withDispatcher()` on it)
*/ */
def props(magicNumber: Int): Props = Props(classOf[DemoActor], magicNumber) def props(magicNumber: Int): Props = Props(new DemoActor(magicNumber))
} }
class DemoActor(magicNumber: Int) extends Actor { class DemoActor(magicNumber: Int) extends Actor {
@ -68,9 +68,16 @@ class DemoActorWrapper extends Actor {
} }
} }
// ... class SomeOtherActor extends Actor {
// Props(new DemoActor(42)) would not be safe
context.actorOf(DemoActor.props(42), "demo") context.actorOf(DemoActor.props(42), "demo")
// ...
//#props-factory
def receive = {
case msg =>
}
//#props-factory
}
//#props-factory //#props-factory
def receive = Actor.emptyBehavior def receive = Actor.emptyBehavior
@ -239,22 +246,13 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
import akka.actor.Props import akka.actor.Props
val props1 = Props[MyActor] val props1 = Props[MyActor]
val props2 = Props(new ActorWithArgs("arg")) // careful, see below
val props3 = Props(classOf[ActorWithArgs], "arg") val props3 = Props(classOf[ActorWithArgs], "arg")
//#creating-props //#creating-props
//#creating-props-deprecated //#creating-props-deprecated
// DEPRECATED: old case class signature // NOT RECOMMENDED within another actor:
val props4 = Props( // encourages to close over enclosing class
creator = { () => new MyActor },
dispatcher = "my-dispatcher")
// DEPRECATED due to duplicate functionality with Props.apply()
val props5 = props1.withCreator(new MyActor)
// DEPRECATED due to duplicate functionality with Props.apply()
val props6 = props1.withCreator(classOf[MyActor])
// NOT RECOMMENDED: encourages to close over enclosing class
val props7 = Props(new MyActor) val props7 = Props(new MyActor)
//#creating-props-deprecated //#creating-props-deprecated
} }
@ -305,7 +303,10 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
"helloBean") "helloBean")
//#creating-indirectly //#creating-indirectly
} }
val actorRef = a.actorRef val actorRef = {
import scala.language.reflectiveCalls
a.actorRef
}
val message = 42 val message = 42
implicit val self = testActor implicit val self = testActor

View file

@ -48,7 +48,7 @@ class DaemonMsgCreateSerializerSpec extends AkkaSpec {
"serialize and de-serialize DaemonMsgCreate with function creator" in { "serialize and de-serialize DaemonMsgCreate with function creator" in {
verifySerialization { verifySerialization {
DaemonMsgCreate( DaemonMsgCreate(
props = Props.empty.withCreator(new MyActor), props = Props(new MyActor),
deploy = Deploy(), deploy = Deploy(),
path = "foo", path = "foo",
supervisor = supervisor) supervisor = supervisor)

View file

@ -320,6 +320,12 @@ class CallingThreadMailbox(_receiver: akka.actor.Cell, val mailboxType: MailboxT
} }
} }
/**
* This is only a marker to be put in the messageQueues stead to make error
* messages pertaining to violated mailbox type requirements less cryptic.
*/
override val messageQueue: MessageQueue = q.get
override def enqueue(receiver: ActorRef, msg: Envelope): Unit = q.get.enqueue(receiver, msg) override def enqueue(receiver: ActorRef, msg: Envelope): Unit = q.get.enqueue(receiver, msg)
override def dequeue(): Envelope = throw new UnsupportedOperationException("CallingThreadMailbox cannot dequeue normally") override def dequeue(): Envelope = throw new UnsupportedOperationException("CallingThreadMailbox cannot dequeue normally")
override def hasMessages: Boolean = q.get.hasMessages override def hasMessages: Boolean = q.get.hasMessages

View file

@ -127,9 +127,9 @@ object TestActorRef {
"$" + akka.util.Helpers.base64(l) "$" + akka.util.Helpers.base64(l)
} }
def apply[T <: Actor](factory: T)(implicit system: ActorSystem): TestActorRef[T] = apply[T](Props.empty.withCreator(factory), randomName) def apply[T <: Actor: ClassTag](factory: T)(implicit system: ActorSystem): TestActorRef[T] = apply[T](Props(factory), randomName)
def apply[T <: Actor](factory: T, name: String)(implicit system: ActorSystem): TestActorRef[T] = apply[T](Props.empty.withCreator(factory), name) def apply[T <: Actor: ClassTag](factory: T, name: String)(implicit system: ActorSystem): TestActorRef[T] = apply[T](Props(factory), name)
def apply[T <: Actor](props: Props)(implicit system: ActorSystem): TestActorRef[T] = apply[T](props, randomName) def apply[T <: Actor](props: Props)(implicit system: ActorSystem): TestActorRef[T] = apply[T](props, randomName)

View file

@ -10,6 +10,7 @@ import akka.dispatch.DispatcherPrerequisites
import scala.concurrent.duration.FiniteDuration import scala.concurrent.duration.FiniteDuration
import akka.dispatch.MessageDispatcher import akka.dispatch.MessageDispatcher
import akka.dispatch.MailboxType import akka.dispatch.MailboxType
import scala.reflect.ClassTag
/** /**
* This is a specialised form of the TestActorRef with support for querying and * This is a specialised form of the TestActorRef with support for querying and
@ -89,13 +90,13 @@ class TestFSMRef[S, D, T <: Actor](
object TestFSMRef { object TestFSMRef {
def apply[S, D, T <: Actor](factory: T)(implicit ev: T <:< FSM[S, D], system: ActorSystem): TestFSMRef[S, D, T] = { def apply[S, D, T <: Actor: ClassTag](factory: T)(implicit ev: T <:< FSM[S, D], system: ActorSystem): TestFSMRef[S, D, T] = {
val impl = system.asInstanceOf[ActorSystemImpl] //TODO ticket #1559 val impl = system.asInstanceOf[ActorSystemImpl] //TODO ticket #1559
new TestFSMRef(impl, Props(creator = () factory), impl.guardian.asInstanceOf[InternalActorRef], TestActorRef.randomName) new TestFSMRef(impl, Props(factory), impl.guardian.asInstanceOf[InternalActorRef], TestActorRef.randomName)
} }
def apply[S, D, T <: Actor](factory: T, name: String)(implicit ev: T <:< FSM[S, D], system: ActorSystem): TestFSMRef[S, D, T] = { def apply[S, D, T <: Actor: ClassTag](factory: T, name: String)(implicit ev: T <:< FSM[S, D], system: ActorSystem): TestFSMRef[S, D, T] = {
val impl = system.asInstanceOf[ActorSystemImpl] //TODO ticket #1559 val impl = system.asInstanceOf[ActorSystemImpl] //TODO ticket #1559
new TestFSMRef(impl, Props(creator = () factory), impl.guardian.asInstanceOf[InternalActorRef], name) new TestFSMRef(impl, Props(factory), impl.guardian.asInstanceOf[InternalActorRef], name)
} }
} }