diff --git a/akka-actor-tests/src/test/java/akka/actor/StashJavaAPI.java b/akka-actor-tests/src/test/java/akka/actor/StashJavaAPI.java index 469c3df206..3487ead16c 100644 --- a/akka-actor-tests/src/test/java/akka/actor/StashJavaAPI.java +++ b/akka-actor-tests/src/test/java/akka/actor/StashJavaAPI.java @@ -6,8 +6,6 @@ import akka.testkit.TestProbe; import org.junit.ClassRule; import org.junit.Test; -import com.typesafe.config.ConfigFactory; - public class StashJavaAPI { @ClassRule @@ -16,14 +14,30 @@ public class StashJavaAPI { private final ActorSystem system = actorSystemResource.getSystem(); - @Test - public void mustBeAbleToUseStash() { - ActorRef ref = system.actorOf(Props.create(StashJavaAPITestActor.class)); - final TestProbe probe = new TestProbe(system); - probe.send(ref, "Hello"); - probe.send(ref, "Hello2"); - probe.send(ref, "Hello12"); - probe.expectMsg(5); + private void testAStashApi(Props props) { + ActorRef ref = system.actorOf(props); + final TestProbe probe = new TestProbe(system); + probe.send(ref, "Hello"); + probe.send(ref, "Hello2"); + probe.send(ref, "Hello12"); + probe.expectMsg(5); } + @Test + public void mustBeAbleToUseStash() { + testAStashApi(Props.create(StashJavaAPITestActors.WithStash.class)); + } + + @Test + public void mustBeAbleToUseUnboundedStash() { + testAStashApi(Props.create(StashJavaAPITestActors.WithUnboundedStash.class)); + } + + @Test + public void mustBeAbleToUseUnrestrictedStash() { + testAStashApi(Props.create(StashJavaAPITestActors.WithUnrestrictedStash.class) + .withMailbox("akka.actor.mailbox.unbounded-deque-based")); + } + + } diff --git a/akka-actor-tests/src/test/java/akka/actor/StashJavaAPITestActor.java b/akka-actor-tests/src/test/java/akka/actor/StashJavaAPITestActor.java deleted file mode 100644 index 5d12f5d8e2..0000000000 --- a/akka-actor-tests/src/test/java/akka/actor/StashJavaAPITestActor.java +++ /dev/null @@ -1,24 +0,0 @@ -package akka.actor; - -import static org.junit.Assert.*; - -public class StashJavaAPITestActor extends UntypedActorWithStash { - int count = 0; - - public void onReceive(Object msg) { - if (msg instanceof String) { - if (count < 0) { - getSender().tell(new Integer(((String) msg).length()), getSelf()); - } else if (count == 2) { - count = -1; - unstashAll(); - } else { - count += 1; - stash(); - } - } else if (msg instanceof Integer) { - int value = ((Integer) msg).intValue(); - assertEquals(value, 5); - } - } -} diff --git a/akka-actor-tests/src/test/java/akka/actor/StashJavaAPITestActors.java b/akka-actor-tests/src/test/java/akka/actor/StashJavaAPITestActors.java new file mode 100644 index 0000000000..435707b9dd --- /dev/null +++ b/akka-actor-tests/src/test/java/akka/actor/StashJavaAPITestActors.java @@ -0,0 +1,53 @@ +package akka.actor; + +import static org.junit.Assert.*; + +public class StashJavaAPITestActors { + + /* + * Helper method to make the tests of UntypedActorWithStash, UntypedActorWithUnboundedStash and + * UntypedActorWithUnrestrictedStash more DRY since mixin is not possible. + */ + private static int testReceive(Object msg, int count, ActorRef sender, ActorRef self, UnrestrictedStash stash) { + if (msg instanceof String) { + if (count < 0) { + sender.tell(new Integer(((String) msg).length()), self); + } else if (count == 2) { + stash.unstashAll(); + return -1; + } else { + stash.stash(); + return count + 1; + } + } else if (msg instanceof Integer) { + int value = ((Integer) msg).intValue(); + assertEquals(value, 5); + } + return count; + } + + public static class WithStash extends UntypedActorWithStash { + int count = 0; + + public void onReceive(Object msg) { + count = testReceive(msg, count, getSender(), getSelf(), this); + } + } + + public static class WithUnboundedStash extends UntypedActorWithUnboundedStash { + int count = 0; + + public void onReceive(Object msg) { + count = testReceive(msg, count, getSender(), getSelf(), this); + } + } + + public static class WithUnrestrictedStash extends UntypedActorWithUnrestrictedStash { + int count = 0; + + public void onReceive(Object msg) { + count = testReceive(msg, count, getSender(), getSelf(), this); + } + } +} + diff --git a/akka-actor/src/main/scala/akka/actor/Stash.scala b/akka-actor/src/main/scala/akka/actor/Stash.scala index fabefdabc5..6cd8e82a3b 100644 --- a/akka-actor/src/main/scala/akka/actor/Stash.scala +++ b/akka-actor/src/main/scala/akka/actor/Stash.scala @@ -30,7 +30,19 @@ import akka.AkkaException * * * Note that the `Stash` trait can only be used together with actors that have a deque-based - * mailbox. + * mailbox. By default Stash based actors request a Deque based mailbox since the stash + * trait extends `RequiresMessageQueue[DequeBasedMessageQueueSemantics]`. + * You can override the default mailbox provided when `DequeBasedMessageQueueSemantics` are requested via config: + *
+ *    akka.actor.mailbox.requirements {
+ *      "akka.dispatch.BoundedDequeBasedMessageQueueSemantics" = your-custom-mailbox
+ *    }
+ *  
+ * Alternatively, you can add your own requirement marker to the actor and configure a mailbox type to be used + * for your marker. + * + * For a `Stash` that also enforces unboundedness of the deque see [[akka.actor.UnboundedStash]]. For a `Stash` + * that does not enforce any mailbox type see [[akka.actor.UnrestrictedStash]]. * * Note that the `Stash` trait must be mixed into (a subclass of) the `Actor` trait before * any trait/class that overrides the `preRestart` callback. This means it's not possible to write @@ -39,10 +51,14 @@ import akka.AkkaException trait Stash extends UnrestrictedStash with RequiresMessageQueue[DequeBasedMessageQueueSemantics] /** - * The `UnboundedStash` trait is a version of `Stash` that enforces an unbounded stash for you actor. + * The `UnboundedStash` trait is a version of [[akka.actor.Stash]] that enforces an unbounded stash for you actor. */ trait UnboundedStash extends UnrestrictedStash with RequiresMessageQueue[UnboundedDequeBasedMessageQueueSemantics] +/** + * A version of [[akka.actor.Stash]] that does not enforce any mailbox type. The proper mailbox has to be configured + * manually, and the mailbox should extend the [[akka.dispatch.DequeBasedMessageQueueSemantics]] marker trait. + */ trait UnrestrictedStash extends Actor { /* The private stash of the actor. It is only accessible using `stash()` and * `unstashAll()`. diff --git a/akka-actor/src/main/scala/akka/actor/UntypedActorWithStash.scala b/akka-actor/src/main/scala/akka/actor/UntypedActorWithStash.scala index 4cf36dcd99..3e8d5d435b 100644 --- a/akka-actor/src/main/scala/akka/actor/UntypedActorWithStash.scala +++ b/akka-actor/src/main/scala/akka/actor/UntypedActorWithStash.scala @@ -29,10 +29,32 @@ package akka.actor * } * } * + * Note that the subclasses of `UntypedActorWithStash` by default request a Deque based mailbox since this class + * implements the `RequiresMessageQueue` marker interface. + * You can override the default mailbox provided when `DequeBasedMessageQueueSemantics` are requested via config: + *
+ *   akka.actor.mailbox.requirements {
+ *     "akka.dispatch.BoundedDequeBasedMessageQueueSemantics" = your-custom-mailbox
+ *   }
+ * 
+ * Alternatively, you can add your own requirement marker to the actor and configure a mailbox type to be used + * for your marker. + * + * For a `Stash` based actor that enforces unbounded deques see [[akka.actor.UntypedActorWithUnboundedStash]]. + * There is also an unrestricted version [[akka.actor.UntypedActorWithUnrestrictedStash]] that does not + * enforce the mailbox type. */ abstract class UntypedActorWithStash extends UntypedActor with Stash /** - * Actor base class that enforces an unbounded stash for the actor. + * Actor base class with `Stash` that enforces an unbounded deque for the actor. The proper mailbox has to be configured + * manually, and the mailbox should extend the [[akka.dispatch.DequeBasedMessageQueueSemantics]] marker trait. + * See [[akka.actor.UntypedActorWithStash]] for details on how `Stash` works. */ abstract class UntypedActorWithUnboundedStash extends UntypedActor with UnboundedStash + +/** + * Actor base class with `Stash` that does not enforce any mailbox type. The mailbox of the actor has to be configured + * manually. See [[akka.actor.UntypedActorWithStash]] for details on how `Stash` works. + */ +abstract class UntypedActorWithUnrestrictedStash extends UntypedActor with UnrestrictedStash diff --git a/akka-docs/rst/java/untyped-actors.rst b/akka-docs/rst/java/untyped-actors.rst index 1fc6cf5644..c2220affe7 100644 --- a/akka-docs/rst/java/untyped-actors.rst +++ b/akka-docs/rst/java/untyped-actors.rst @@ -708,6 +708,14 @@ mailbox. This way, the stashed messages can be processed in the same order as they have been received originally. An actor that extends ``UntypedActorWithStash`` will automatically get a deque-based mailbox. +.. note:: + + The abstract class ``UntypedActorWithStash`` implements the marker + interface ``RequiresMessageQueue`` + which requests the system to automatically choose a deque based + mailbox implementation for the actor. If you want more + control over the mailbox, see the documentation on mailboxes: :ref:`mailboxes-java`. + Here is an example of the ``UntypedActorWithStash`` class in action: .. includecode:: code/docs/actor/UntypedActorDocTest.java#import-stash diff --git a/akka-docs/rst/scala/actors.rst b/akka-docs/rst/scala/actors.rst index 9c7e44acd8..2b9b83f604 100644 --- a/akka-docs/rst/scala/actors.rst +++ b/akka-docs/rst/scala/actors.rst @@ -800,13 +800,13 @@ stashed messages can be "unstashed", thereby prepending them to the actor's mailbox. This way, the stashed messages can be processed in the same order as they have been received originally. -.. warning:: +.. note:: - Please note that the ``Stash`` can only be used together with actors - that have a deque-based mailbox. For this, configure the - ``mailbox-type`` of the dispatcher or in the deployment of the actor - to be a deque-based mailbox, such as ``akka.dispatch.UnboundedDequeBasedMailbox`` - (see :ref:`mailboxes-scala`). + The trait ``Stash`` extends the marker trait + ``RequiresMessageQueue[DequeBasedMessageQueueSemantics]`` which + requests the system to automatically choose a deque based + mailbox implementation for the actor. If you want more control over the + mailbox, see the documentation on mailboxes: :ref:`mailboxes-scala`. Here is an example of the ``Stash`` in action: