diff --git a/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/BehaviorBuilderTest.java b/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/BehaviorBuilderTest.java index 5549d14e38..ea0a8f0646 100644 --- a/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/BehaviorBuilderTest.java +++ b/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/BehaviorBuilderTest.java @@ -4,6 +4,9 @@ package akka.actor.typed.javadsl; +import akka.actor.testkit.typed.javadsl.TestKitJunitResource; +import akka.actor.testkit.typed.javadsl.TestProbe; +import org.junit.ClassRule; import org.junit.Test; import org.scalatest.junit.JUnitSuite; @@ -15,9 +18,13 @@ import java.util.ArrayList; import static akka.actor.typed.javadsl.Behaviors.same; import static akka.actor.typed.javadsl.Behaviors.stopped; +import static org.junit.Assert.assertEquals; /** Test creating [[Behavior]]s using [[BehaviorBuilder]] */ public class BehaviorBuilderTest extends JUnitSuite { + + @ClassRule public static final TestKitJunitResource testKit = new TestKitJunitResource(); + interface Message {} static final class One implements Message { @@ -28,7 +35,6 @@ public class BehaviorBuilderTest extends JUnitSuite { static final class MyList extends ArrayList implements Message {}; - @Test public void shouldCompile() { Behavior b = Behaviors.receive(Message.class) @@ -54,6 +60,86 @@ public class BehaviorBuilderTest extends JUnitSuite { .build(); } + @Test + public void caseSelectedInOrderAdded() { + final TestProbe probe = testKit.createTestProbe(); + Behavior behavior = + BehaviorBuilder.create() + .onMessage( + String.class, + (context, msg) -> { + probe.ref().tell("handler 1: " + msg); + return Behaviors.same(); + }) + .onMessage( + String.class, + (context, msg) -> { + probe.ref().tell("handler 2: " + msg); + return Behaviors.same(); + }) + .build(); + ActorRef ref = testKit.spawn(behavior); + ref.tell("message"); + probe.expectMessage("handler 1: message"); + } + + @Test + public void handleMessageBasedOnEquality() { + final TestProbe probe = testKit.createTestProbe(); + Behavior behavior = + BehaviorBuilder.create() + .onMessageEquals( + "message", + (context) -> { + probe.ref().tell("got it"); + return Behaviors.same(); + }) + .build(); + ActorRef ref = testKit.spawn(behavior); + ref.tell("message"); + probe.expectMessage("got it"); + } + + @Test + public void applyPredicate() { + final TestProbe probe = testKit.createTestProbe(); + Behavior behavior = + BehaviorBuilder.create() + .onMessage( + String.class, + (msg) -> "other".equals(msg), + (context, msg) -> { + probe.ref().tell("handler 1: " + msg); + return Behaviors.same(); + }) + .onMessage( + String.class, + (context, msg) -> { + probe.ref().tell("handler 2: " + msg); + return Behaviors.same(); + }) + .build(); + ActorRef ref = testKit.spawn(behavior); + ref.tell("message"); + probe.expectMessage("handler 2: message"); + } + + @Test + public void catchAny() { + final TestProbe probe = testKit.createTestProbe(); + Behavior behavior = + BehaviorBuilder.create() + .onAnyMessage( + (context, msg) -> { + probe.ref().tell(msg); + return same(); + }) + .build(); + ActorRef ref = testKit.spawn(behavior); + ref.tell("message"); + probe.expectMessage("message"); + } + interface CounterMessage {}; static final class Increase implements CounterMessage {}; @@ -92,6 +178,12 @@ public class BehaviorBuilderTest extends JUnitSuite { @Test public void testImmutableCounter() { - Behavior immutable = immutableCounter(0); + ActorRef ref = testKit.spawn(immutableCounter(0)); + TestProbe probe = testKit.createTestProbe(); + ref.tell(new Get(probe.getRef())); + assertEquals(0, probe.expectMessageClass(Got.class).n); + ref.tell(new Increase()); + ref.tell(new Get(probe.getRef())); + assertEquals(1, probe.expectMessageClass(Got.class).n); } } diff --git a/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/ReceiveBuilderTest.java b/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/ReceiveBuilderTest.java index aeeac4588b..71c302870d 100644 --- a/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/ReceiveBuilderTest.java +++ b/akka-actor-typed-tests/src/test/java/akka/actor/typed/javadsl/ReceiveBuilderTest.java @@ -4,16 +4,23 @@ package akka.actor.typed.javadsl; +import akka.actor.testkit.typed.javadsl.TestKitJunitResource; +import akka.actor.testkit.typed.javadsl.TestProbe; +import akka.actor.typed.ActorRef; +import org.junit.ClassRule; import org.junit.Test; import org.scalatest.junit.JUnitSuite; import akka.actor.typed.Behavior; +import static akka.actor.typed.javadsl.Behaviors.same; import static org.junit.Assert.assertEquals; /** Test creating [[MutableActor]]s using [[ReceiveBuilder]] */ public class ReceiveBuilderTest extends JUnitSuite { + @ClassRule public static final TestKitJunitResource testKit = new TestKitJunitResource(); + @Test public void testMutableCounter() { Behavior mutable = @@ -36,7 +43,7 @@ public class ReceiveBuilderTest extends JUnitSuite { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(BehaviorBuilderTest.Increase.class, this::receiveIncrease) .onMessage(BehaviorBuilderTest.Get.class, this::receiveGet) .build(); @@ -56,7 +63,7 @@ public class ReceiveBuilderTest extends JUnitSuite { @Override public Receive createReceive() { assertEquals(42, value); - return receiveBuilder().build(); + return newReceiveBuilder().build(); } } @@ -65,4 +72,67 @@ public class ReceiveBuilderTest extends JUnitSuite { MyAbstractBehavior mutable = new MyAbstractBehavior(42); assertEquals(Behaviors.unhandled(), mutable.receive(null, new BehaviorBuilderTest.Increase())); } + + @Test + public void caseSelectedInOrderAdded() { + final TestProbe probe = testKit.createTestProbe(); + Behavior behavior = + ReceiveBuilder.create() + .onMessage( + String.class, + msg -> { + probe.ref().tell("handler 1: " + msg); + return Behaviors.same(); + }) + .onMessage( + String.class, + msg -> { + probe.ref().tell("handler 2: " + msg); + return Behaviors.same(); + }) + .build(); + ActorRef ref = testKit.spawn(behavior); + ref.tell("message"); + probe.expectMessage("handler 1: message"); + } + + @Test + public void applyPredicate() { + final TestProbe probe = testKit.createTestProbe(); + Behavior behavior = + ReceiveBuilder.create() + .onMessage( + String.class, + msg -> "other".equals(msg), + msg -> { + probe.ref().tell("handler 1: " + msg); + return Behaviors.same(); + }) + .onMessage( + String.class, + msg -> { + probe.ref().tell("handler 2: " + msg); + return Behaviors.same(); + }) + .build(); + ActorRef ref = testKit.spawn(behavior); + ref.tell("message"); + probe.expectMessage("handler 2: message"); + } + + @Test + public void catchAny() { + final TestProbe probe = testKit.createTestProbe(); + Behavior behavior = + ReceiveBuilder.create() + .onAnyMessage( + msg -> { + probe.ref().tell(msg); + return same(); + }) + .build(); + ActorRef ref = testKit.spawn(behavior); + ref.tell("message"); + probe.expectMessage("message"); + } } diff --git a/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/InteractionPatternsTest.java b/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/InteractionPatternsTest.java index b2d3536de5..8b8faa93ec 100644 --- a/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/InteractionPatternsTest.java +++ b/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/InteractionPatternsTest.java @@ -207,7 +207,7 @@ public class InteractionPatternsTest extends JUnitSuite { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage( Translate.class, cmd -> { @@ -603,7 +603,7 @@ public class InteractionPatternsTest extends JUnitSuite { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage( Wallet.class, (wallet) -> { diff --git a/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/OOIntroTest.java b/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/OOIntroTest.java index ca8650ccb4..0af72b02cc 100644 --- a/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/OOIntroTest.java +++ b/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/OOIntroTest.java @@ -5,15 +5,11 @@ package jdocs.akka.typed; // #imports -import akka.NotUsed; import akka.actor.typed.ActorRef; import akka.actor.typed.ActorSystem; import akka.actor.typed.Behavior; import akka.actor.typed.Terminated; -import akka.actor.typed.javadsl.AbstractBehavior; -import akka.actor.typed.javadsl.ActorContext; -import akka.actor.typed.javadsl.Behaviors; -import akka.actor.typed.javadsl.Receive; +import akka.actor.typed.javadsl.*; // #imports import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -112,29 +108,32 @@ public class OOIntroTest { @Override public Receive createReceive() { - return receiveBuilder() - .onMessage( - GetSession.class, - getSession -> { - ActorRef client = getSession.replyTo; - ActorRef ses = - context.spawn( - session(context.getSelf(), getSession.screenName, client), - URLEncoder.encode(getSession.screenName, StandardCharsets.UTF_8.name())); - // narrow to only expose PostMessage - client.tell(new SessionGranted(ses.narrow())); - sessions.add(ses); - return this; - }) - .onMessage( - PublishSessionMessage.class, - pub -> { - NotifyClient notification = - new NotifyClient((new MessagePosted(pub.screenName, pub.message))); - sessions.forEach(s -> s.tell(notification)); - return this; - }) - .build(); + ReceiveBuilder builder = newReceiveBuilder(); + + builder.onMessage( + GetSession.class, + getSession -> { + ActorRef client = getSession.replyTo; + ActorRef ses = + context.spawn( + session(context.getSelf(), getSession.screenName, client), + URLEncoder.encode(getSession.screenName, StandardCharsets.UTF_8.name())); + // narrow to only expose PostMessage + client.tell(new SessionGranted(ses.narrow())); + sessions.add(ses); + return this; + }); + + builder.onMessage( + PublishSessionMessage.class, + pub -> { + NotifyClient notification = + new NotifyClient((new MessagePosted(pub.screenName, pub.message))); + sessions.forEach(s -> s.tell(notification)); + return this; + }); + + return builder.build(); } } diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/AbstractBehavior.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/AbstractBehavior.scala index 22b4a35ce3..5a63fb2cd5 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/AbstractBehavior.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/AbstractBehavior.scala @@ -42,13 +42,13 @@ abstract class AbstractBehavior[T] extends ExtensibleBehavior[T] { /** * Implement this to define how messages and signals are processed. Use the - * [[AbstractBehavior.receiveBuilder]] to define the message dispatch. + * [[AbstractBehavior.newReceiveBuilder]] to define the message dispatch. */ def createReceive: Receive[T] /** - * Create a [[ReceiveBuilder]] to define the message dispatch of the `Behavior`. + * Create a new [[ReceiveBuilder]] to define the message dispatch of the `Behavior`. * Typically used from [[AbstractBehavior.createReceive]]. */ - def receiveBuilder: ReceiveBuilder[T] = ReceiveBuilder.create + def newReceiveBuilder: ReceiveBuilder[T] = ReceiveBuilder.create } diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala index be5d87a270..e99462326f 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala @@ -5,29 +5,34 @@ package akka.actor.typed.javadsl import scala.annotation.tailrec - -import akka.japi.function.{ Function, Function2, Predicate } +import akka.japi.function.{ Function ⇒ JFunction } +import akka.japi.function.{ Function2 ⇒ JFunction2 } +import akka.japi.function.{ Predicate ⇒ JPredicate } import akka.annotation.InternalApi -import akka.actor.typed -import akka.actor.typed.{ Behavior, ExtensibleBehavior, Signal } - +import akka.actor.typed.Behavior +import akka.actor.typed.ExtensibleBehavior +import akka.actor.typed.Signal +import akka.actor.typed.TypedActorContext import akka.actor.typed.Behavior.unhandled - import BehaviorBuilder._ +import akka.util.OptionVal /** - * Used for creating a [[Behavior]] by 'chaining' message and signal handlers. + * Immutable builder used for creating a [[Behavior]] by 'chaining' message and signal handlers. * * When handling a message or signal, this [[Behavior]] will consider all handlers in the order they were added, * looking for the first handler for which both the type and the (optional) predicate match. * * @tparam T the common superclass of all supported messages. */ -class BehaviorBuilder[T] private ( - private val messageHandlers: List[Case[T, T]], - private val signalHandlers: List[Case[T, Signal]] +final class BehaviorBuilder[T] private ( + messageHandlers: List[Case[T, T]], + signalHandlers: List[Case[T, Signal]] ) { + /** + * Build a Behavior from the current state of the builder + */ def build(): Behavior[T] = new BuiltBehavior(messageHandlers.reverse, signalHandlers.reverse) /** @@ -36,10 +41,10 @@ class BehaviorBuilder[T] private ( * @param type type of message to match * @param handler action to apply if the type matches * @tparam M type of message to match - * @return a new behavior with the specified handling appended + * @return a new behavior builder with the specified handling appended */ - def onMessage[M <: T](`type`: Class[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - withMessage(`type`, None, (i1: ActorContext[T], msg: T) ⇒ handler.apply(i1, msg.asInstanceOf[M])) + def onMessage[M <: T](`type`: Class[M], handler: JFunction2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = + withMessage(OptionVal.Some(`type`), OptionVal.None, handler) /** * Add a new predicated case to the message handling. @@ -48,14 +53,13 @@ class BehaviorBuilder[T] private ( * @param test a predicate that will be evaluated on the argument if the type matches * @param handler action to apply if the type matches and the predicate returns true * @tparam M type of message to match - * @return a new behavior with the specified handling appended + * @return a new behavior builder with the specified handling appended */ - def onMessage[M <: T](`type`: Class[M], test: Predicate[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = + def onMessage[M <: T](`type`: Class[M], test: JPredicate[M], handler: JFunction2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = withMessage( - `type`, - Some((t: T) ⇒ test.test(t.asInstanceOf[M])), - (i1: ActorContext[T], msg: T) ⇒ handler.apply(i1, msg.asInstanceOf[M]) - ) + OptionVal.Some(`type`), + OptionVal.Some((t: T) ⇒ test.test(t.asInstanceOf[M])), + handler) /** * Add a new case to the message handling without compile time type check. @@ -65,20 +69,36 @@ class BehaviorBuilder[T] private ( * * @param type type of message to match * @param handler action to apply when the type matches - * @return a new behavior with the specified handling appended + * @return a new behavior builder with the specified handling appended */ - def onMessageUnchecked[M <: T](`type`: Class[_ <: T], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - withMessage(`type`, None, (i1: ActorContext[T], msg: T) ⇒ handler.apply(i1, msg.asInstanceOf[M])) + def onMessageUnchecked[M <: T](`type`: Class[_ <: T], handler: JFunction2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = + withMessage[M]( + OptionVal.Some(`type`.asInstanceOf[Class[M]]), OptionVal.None, handler) /** * Add a new case to the message handling matching equal messages. * * @param msg the message to compare to * @param handler action to apply when the message matches - * @return a new behavior with the specified handling appended + * @return a new behavior builder with the specified handling appended */ - def onMessageEquals(msg: T, handler: Function[ActorContext[T], Behavior[T]]): BehaviorBuilder[T] = - withMessage(msg.getClass, Some(_.equals(msg)), (ctx: ActorContext[T], _: T) ⇒ handler.apply(ctx)) + def onMessageEquals(msg: T, handler: JFunction[ActorContext[T], Behavior[T]]): BehaviorBuilder[T] = + withMessage[T]( + OptionVal.Some(msg.getClass.asInstanceOf[Class[T]]), + OptionVal.Some(_.equals(msg)), + new JFunction2[ActorContext[T], T, Behavior[T]] { + override def apply(ctx: ActorContext[T], msg: T): Behavior[T] = handler.apply(ctx) + }) + + /** + * Add a new case to the message handling matching any message. Subsequent `onMessage` clauses will + * never see any messages. + * + * @param handler action to apply for any message + * @return a new behavior builder with the specified handling appended + */ + def onAnyMessage(handler: JFunction2[ActorContext[T], T, Behavior[T]]): BehaviorBuilder[T] = + withMessage(OptionVal.None, OptionVal.None, handler) /** * Add a new case to the signal handling. @@ -86,10 +106,13 @@ class BehaviorBuilder[T] private ( * @param type type of signal to match * @param handler action to apply if the type matches * @tparam M type of signal to match - * @return a new behavior with the specified handling appended + * @return a new behavior builder with the specified handling appended */ - def onSignal[M <: Signal](`type`: Class[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - withSignal(`type`, None, (ctx: ActorContext[T], signal: Signal) ⇒ handler.apply(ctx, signal.asInstanceOf[M])) + def onSignal[M <: Signal](`type`: Class[M], handler: JFunction2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = + withSignal( + `type`, + OptionVal.None, + handler.asInstanceOf[JFunction2[ActorContext[T], Signal, Behavior[T]]]) /** * Add a new predicated case to the signal handling. @@ -98,168 +121,87 @@ class BehaviorBuilder[T] private ( * @param test a predicate that will be evaluated on the argument if the type matches * @param handler action to apply if the type matches and the predicate returns true * @tparam M type of signal to match - * @return a new behavior with the specified handling appended + * @return a new behavior builder with the specified handling appended */ - def onSignal[M <: Signal](`type`: Class[M], test: Predicate[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = + def onSignal[M <: Signal](`type`: Class[M], test: JPredicate[M], handler: JFunction2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = withSignal( `type`, - Some((t: Signal) ⇒ test.test(t.asInstanceOf[M])), - (ctx: ActorContext[T], signal: Signal) ⇒ handler.apply(ctx, signal.asInstanceOf[M]) + OptionVal.Some((t: Signal) ⇒ test.test(t.asInstanceOf[M])), + handler.asInstanceOf[JFunction2[ActorContext[T], Signal, Behavior[T]]] ) - /** - * Add a new case to the signal handling without compile time type check. - * - * Should normally not be used, but when matching on class with generic type - * argument it can be useful, e.g. GenMsg.class and (ActorContext ctx, GenMsg<String> list) -> {...} - * - * @param type type of signal to match - * @param handler action to apply when the type matches - * @return a new behavior with the specified handling appended - */ - def onSignalUnchecked[M <: Signal](`type`: Class[_ <: Signal], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - withSignal(`type`, None, (ctx: ActorContext[T], signal: Signal) ⇒ handler.apply(ctx, signal.asInstanceOf[M])) - /** * Add a new case to the signal handling matching equal signals. * * @param signal the signal to compare to * @param handler action to apply when the message matches - * @return a new behavior with the specified handling appended + * @return a new behavior builder with the specified handling appended */ def onSignalEquals(signal: Signal, handler: Function[ActorContext[T], Behavior[T]]): BehaviorBuilder[T] = - withSignal(signal.getClass, Some(_.equals(signal)), (ctx: ActorContext[T], _: Signal) ⇒ handler.apply(ctx)) + withSignal( + signal.getClass, + OptionVal.Some(_.equals(signal)), + new JFunction2[ActorContext[T], Signal, Behavior[T]] { + override def apply(ctx: ActorContext[T], signal: Signal): Behavior[T] = { + handler.apply(ctx) + } + }) - private def withMessage(`type`: Class[_ <: T], test: Option[T ⇒ Boolean], handler: (ActorContext[T], T) ⇒ Behavior[T]): BehaviorBuilder[T] = - new BehaviorBuilder[T](Case[T, T](`type`, test, handler) +: messageHandlers, signalHandlers) + private def withMessage[M <: T](clazz: OptionVal[Class[M]], test: OptionVal[M ⇒ Boolean], handler: JFunction2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = { + val newCase = Case( + clazz, + test, + handler + ) + new BehaviorBuilder[T](newCase.asInstanceOf[Case[T, T]] +: messageHandlers, signalHandlers) + } - private def withSignal[M <: Signal](`type`: Class[M], test: Option[Signal ⇒ Boolean], handler: (ActorContext[T], Signal) ⇒ Behavior[T]): BehaviorBuilder[T] = - new BehaviorBuilder[T](messageHandlers, Case[T, Signal](`type`, test, handler) +: signalHandlers) + private def withSignal[M <: Signal](`type`: Class[M], test: OptionVal[Signal ⇒ Boolean], handler: JFunction2[ActorContext[T], Signal, Behavior[T]]): BehaviorBuilder[T] = { + new BehaviorBuilder[T]( + messageHandlers, + Case(OptionVal.Some(`type`), test, handler).asInstanceOf[Case[T, Signal]] +: signalHandlers + ) + } } object BehaviorBuilder { - def create[T]: BehaviorBuilder[T] = new BehaviorBuilder[T](Nil, Nil) + private val _empty = new BehaviorBuilder[Nothing](Nil, Nil) + + // used for both matching signals and messages so we throw away types after they are enforced by the builder API above /** INTERNAL API */ @InternalApi - private[javadsl] final case class Case[BT, MT](`type`: Class[_ <: MT], test: Option[MT ⇒ Boolean], handler: (ActorContext[BT], MT) ⇒ Behavior[BT]) + private[javadsl] final case class Case[BT, MT](`type`: OptionVal[Class[_ <: MT]], test: OptionVal[MT ⇒ Boolean], handler: JFunction2[ActorContext[BT], MT, Behavior[BT]]) /** - * Start a new behavior chain starting with this case. - * - * @param type type of message to match - * @param handler action to apply if the type matches - * @tparam T type of behavior to create - * @tparam M type of message to match - * @return a new behavior with the specified handling appended + * @return new empty immutable behavior builder. */ - def message[T, M <: T](`type`: Class[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onMessage(`type`, handler) - - /** - * Start a new behavior chain starting with this predicated case. - * - * @param type type of message to match - * @param test a predicate that will be evaluated on the argument if the type matches - * @param handler action to apply if the type matches and the predicate returns true - * @tparam T type of behavior to create - * @tparam M type of message to match - * @return a new behavior with the specified handling appended - */ - def message[T, M <: T](`type`: Class[M], test: Predicate[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onMessage(`type`, test, handler) - - /** - * Start a new behavior chain starting with a handler without compile time type check. - * - * Should normally not be used, but when matching on class with generic type - * argument it can be useful, e.g. List.class and (List<String> list) -> {...} - * - * @param type type of message to match - * @param handler action to apply when the type matches - * @return a new behavior with the specified handling appended - */ - def messageUnchecked[T, M <: T](`type`: Class[_ <: T], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onMessageUnchecked(`type`, handler) - - /** - * Start a new behavior chain starting with a handler for equal messages. - * - * @param msg the message to compare to - * @param handler action to apply when the message matches - * @tparam T type of behavior to create - * @return a new behavior with the specified handling appended - */ - def messageEquals[T](msg: T, handler: Function[ActorContext[T], Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onMessageEquals(msg, handler) - - /** - * Start a new behavior chain starting with this signal case. - * - * @param type type of signal to match - * @param handler action to apply if the type matches - * @tparam T type of behavior to create - * @tparam M type of signal to match - * @return a new behavior with the specified handling appended - */ - def signal[T, M <: Signal](`type`: Class[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onSignal(`type`, handler) - - /** - * Start a new behavior chain starting with this predicated signal case. - * - * @param type type of signals to match - * @param test a predicate that will be evaluated on the argument if the type matches - * @param handler action to apply if the type matches and the predicate returns true - * @tparam T type of behavior to create - * @tparam M type of signal to match - * @return a new behavior with the specified handling appended - */ - def signal[T, M <: Signal](`type`: Class[M], test: Predicate[M], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onSignal(`type`, test, handler) - - /** - * Start a new behavior chain starting with this unchecked signal case. - * - * Should normally not be used, but when matching on class with generic type - * argument it can be useful, e.g. GenMsg.class and (ActorContext ctx, GenMsg<String> list) -> {...} - * - * @param type type of signal to match - * @param handler action to apply when the type matches - * @return a new behavior with the specified handling appended - */ - def signalUnchecked[T, M <: Signal](`type`: Class[_ <: Signal], handler: Function2[ActorContext[T], M, Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onSignalUnchecked(`type`, handler) - - /** - * Start a new behavior chain starting with a handler for this specific signal. - * - * @param signal the signal to compare to - * @param handler action to apply when the message matches - * @tparam T type of behavior to create - * @return a new behavior with the specified handling appended - */ - def signalEquals[T](signal: Signal, handler: Function[ActorContext[T], Behavior[T]]): BehaviorBuilder[T] = - BehaviorBuilder.create[T].onSignalEquals(signal, handler) - + def create[T]: BehaviorBuilder[T] = _empty.asInstanceOf[BehaviorBuilder[T]] } -private class BuiltBehavior[T]( - private val messageHandlers: List[Case[T, T]], - private val signalHandlers: List[Case[T, Signal]] +/** + * The concrete behavior + * + * INTERNAL API + */ +@InternalApi +private final class BuiltBehavior[T]( + messageHandlers: List[Case[T, T]], + signalHandlers: List[Case[T, Signal]] ) extends ExtensibleBehavior[T] { - override def receive(ctx: typed.TypedActorContext[T], msg: T): Behavior[T] = receive[T](ctx.asJava, msg, messageHandlers) + override def receive(ctx: TypedActorContext[T], msg: T): Behavior[T] = receive(ctx.asJava, msg, messageHandlers) - override def receiveSignal(ctx: typed.TypedActorContext[T], msg: Signal): Behavior[T] = receive[Signal](ctx.asJava, msg, signalHandlers) + override def receiveSignal(ctx: TypedActorContext[T], msg: Signal): Behavior[T] = receive(ctx.asJava, msg, signalHandlers) @tailrec private def receive[M](ctx: ActorContext[T], msg: M, handlers: List[Case[T, M]]): Behavior[T] = handlers match { case Case(cls, predicate, handler) :: tail ⇒ - if (cls.isAssignableFrom(msg.getClass) && (predicate.isEmpty || predicate.get.apply(msg))) handler(ctx, msg) - else receive[M](ctx, msg, tail) - case _ ⇒ + if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.apply(msg))) + handler(ctx, msg) + else receive(ctx, msg, tail) + case Nil ⇒ unhandled[T] } diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala index edd484034d..1768e22d02 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala @@ -5,26 +5,29 @@ package akka.actor.typed.javadsl import scala.annotation.tailrec -import akka.japi.function.{ Creator, Function, Predicate } +import akka.japi.function.Creator +import akka.japi.function.{ Function ⇒ JFunction } +import akka.japi.function.{ Predicate ⇒ JPredicate } import akka.actor.typed.{ Behavior, Signal } import akka.annotation.InternalApi +import akka.util.OptionVal /** - * Used when implementing [[AbstractBehavior]]. + * Mutable builder used when implementing [[AbstractBehavior]]. * * When handling a message or signal, this [[Behavior]] will consider all handlers in the order they were added, * looking for the first handler for which both the type and the (optional) predicate match. * * @tparam T the common superclass of all supported messages. */ -class ReceiveBuilder[T] private ( - private val messageHandlers: List[ReceiveBuilder.Case[T, T]], - private val signalHandlers: List[ReceiveBuilder.Case[T, Signal]] +final class ReceiveBuilder[T] private ( + private var messageHandlers: List[ReceiveBuilder.Case[T, T]], + private var signalHandlers: List[ReceiveBuilder.Case[T, Signal]] ) { import ReceiveBuilder.Case - def build(): Receive[T] = new BuiltReceive(messageHandlers.reverse, signalHandlers.reverse) + def build(): Receive[T] = new BuiltReceive[T](messageHandlers.reverse, signalHandlers.reverse) /** * Add a new case to the message handling. @@ -32,10 +35,10 @@ class ReceiveBuilder[T] private ( * @param type type of message to match * @param handler action to apply if the type matches * @tparam M type of message to match - * @return a new behavior with the specified handling appended + * @return this behavior builder */ - def onMessage[M <: T](`type`: Class[M], handler: Function[M, Behavior[T]]): ReceiveBuilder[T] = - withMessage(`type`, None, msg ⇒ handler.apply(msg.asInstanceOf[M])) + def onMessage[M <: T](`type`: Class[M], handler: JFunction[M, Behavior[T]]): ReceiveBuilder[T] = + withMessage(OptionVal.Some(`type`), OptionVal.None, handler) /** * Add a new predicated case to the message handling. @@ -44,14 +47,10 @@ class ReceiveBuilder[T] private ( * @param test a predicate that will be evaluated on the argument if the type matches * @param handler action to apply if the type matches and the predicate returns true * @tparam M type of message to match - * @return a new behavior with the specified handling appended + * @return this behavior builder */ - def onMessage[M <: T](`type`: Class[M], test: Predicate[M], handler: Function[M, Behavior[T]]): ReceiveBuilder[T] = - withMessage( - `type`, - Some((t: T) ⇒ test.test(t.asInstanceOf[M])), - msg ⇒ handler.apply(msg.asInstanceOf[M]) - ) + def onMessage[M <: T](`type`: Class[M], test: JPredicate[M], handler: JFunction[M, Behavior[T]]): ReceiveBuilder[T] = + withMessage(OptionVal.Some(`type`), OptionVal.Some(test), handler) /** * Add a new case to the message handling without compile time type check. @@ -61,20 +60,35 @@ class ReceiveBuilder[T] private ( * * @param type type of message to match * @param handler action to apply when the type matches - * @return a new behavior with the specified handling appended + * @return this behavior builder */ - def onMessageUnchecked[M <: T](`type`: Class[_ <: T], handler: Function[M, Behavior[T]]): ReceiveBuilder[T] = - withMessage(`type`, None, msg ⇒ handler.apply(msg.asInstanceOf[M])) + def onMessageUnchecked[M <: T](`type`: Class[_ <: T], handler: JFunction[M, Behavior[T]]): ReceiveBuilder[T] = + withMessage[M](OptionVal.Some(`type`.asInstanceOf[Class[M]]), OptionVal.None, handler) /** * Add a new case to the message handling matching equal messages. * * @param msg the message to compare to * @param handler action to apply when the message matches - * @return a new behavior with the specified handling appended + * @return this behavior builder */ def onMessageEquals(msg: T, handler: Creator[Behavior[T]]): ReceiveBuilder[T] = - withMessage(msg.getClass, Some(_.equals(msg)), _ ⇒ handler.create()) + withMessage(OptionVal.Some(msg.getClass), OptionVal.Some(new JPredicate[T] { + override def test(param: T): Boolean = param == (msg) + }), new JFunction[T, Behavior[T]] { + // invoke creator without the message + override def apply(param: T): Behavior[T] = handler.create() + }) + + /** + * Add a new case to the message handling matching any message. Subsequent `onMessage` clauses will + * never see any messages. + * + * @param handler action to apply for any message + * @return this behavior builder + */ + def onAnyMessage(handler: JFunction[T, Behavior[T]]): ReceiveBuilder[T] = + withMessage(OptionVal.None, OptionVal.None, handler) /** * Add a new case to the signal handling. @@ -82,10 +96,10 @@ class ReceiveBuilder[T] private ( * @param type type of signal to match * @param handler action to apply if the type matches * @tparam M type of signal to match - * @return a new behavior with the specified handling appended + * @return this behavior builder */ - def onSignal[M <: Signal](`type`: Class[M], handler: Function[M, Behavior[T]]): ReceiveBuilder[T] = - withSignal(`type`, None, signal ⇒ handler.apply(signal.asInstanceOf[M])) + def onSignal[M <: Signal](`type`: Class[M], handler: JFunction[M, Behavior[T]]): ReceiveBuilder[T] = + withSignal(`type`, OptionVal.None, handler) /** * Add a new predicated case to the signal handling. @@ -94,60 +108,55 @@ class ReceiveBuilder[T] private ( * @param test a predicate that will be evaluated on the argument if the type matches * @param handler action to apply if the type matches and the predicate returns true * @tparam M type of signal to match - * @return a new behavior with the specified handling appended + * @return this behavior builder */ - def onSignal[M <: Signal](`type`: Class[M], test: Predicate[M], handler: Function[M, Behavior[T]]): ReceiveBuilder[T] = - withSignal( - `type`, - Some((t: Signal) ⇒ test.test(t.asInstanceOf[M])), - signal ⇒ handler.apply(signal.asInstanceOf[M]) - ) - - /** - * Add a new case to the signal handling without compile time type check. - * - * Should normally not be used, but when matching on class with generic type - * argument it can be useful, e.g. GenMsg.class and (ActorContext ctx, GenMsg<String> list) -> {...} - * - * @param type type of signal to match - * @param handler action to apply when the type matches - * @return a new behavior with the specified handling appended - */ - def onSignalUnchecked[M <: Signal](`type`: Class[_ <: Signal], handler: Function[M, Behavior[T]]): ReceiveBuilder[T] = - withSignal(`type`, None, signal ⇒ handler.apply(signal.asInstanceOf[M])) + def onSignal[M <: Signal](`type`: Class[M], test: JPredicate[M], handler: JFunction[M, Behavior[T]]): ReceiveBuilder[T] = + withSignal(`type`, OptionVal.Some(test), handler) /** * Add a new case to the signal handling matching equal signals. * * @param signal the signal to compare to * @param handler action to apply when the message matches - * @return a new behavior with the specified handling appended + * @return this behavior builder */ def onSignalEquals(signal: Signal, handler: Creator[Behavior[T]]): ReceiveBuilder[T] = - withSignal(signal.getClass, Some(_.equals(signal)), _ ⇒ handler.create()) + withSignal(signal.getClass, OptionVal.Some(new JPredicate[Signal] { + override def test(param: Signal): Boolean = param == signal + }), new JFunction[Signal, Behavior[T]] { + override def apply(param: Signal): Behavior[T] = handler.create() + }) - private def withMessage(`type`: Class[_ <: T], test: Option[T ⇒ Boolean], handler: T ⇒ Behavior[T]): ReceiveBuilder[T] = - new ReceiveBuilder[T](Case[T, T](`type`, test, handler) +: messageHandlers, signalHandlers) + private def withMessage[M <: T](`type`: OptionVal[Class[M]], test: OptionVal[JPredicate[M]], handler: JFunction[M, Behavior[T]]): ReceiveBuilder[T] = { + messageHandlers = Case[T, M](`type`, test, handler).asInstanceOf[Case[T, T]] +: messageHandlers + this + } - private def withSignal[M <: Signal](`type`: Class[M], test: Option[Signal ⇒ Boolean], handler: Signal ⇒ Behavior[T]): ReceiveBuilder[T] = - new ReceiveBuilder[T](messageHandlers, Case[T, Signal](`type`, test, handler) +: signalHandlers) + private def withSignal[M <: Signal](`type`: Class[M], test: OptionVal[JPredicate[M]], handler: JFunction[M, Behavior[T]]): ReceiveBuilder[T] = { + signalHandlers = Case[T, M](OptionVal.Some(`type`), test, handler).asInstanceOf[Case[T, Signal]] +: signalHandlers + this + } } object ReceiveBuilder { + /** Create a new mutable receive builder */ def create[T]: ReceiveBuilder[T] = new ReceiveBuilder[T](Nil, Nil) /** INTERNAL API */ @InternalApi - private[javadsl] final case class Case[BT, MT](`type`: Class[_ <: MT], test: Option[MT ⇒ Boolean], handler: MT ⇒ Behavior[BT]) + private[javadsl] final case class Case[BT, MT](`type`: OptionVal[Class[_ <: MT]], test: OptionVal[JPredicate[MT]], handler: JFunction[MT, Behavior[BT]]) } /** * Receive type for [[AbstractBehavior]] + * + * INTERNAL API */ +@InternalApi private final class BuiltReceive[T]( - private val messageHandlers: List[ReceiveBuilder.Case[T, T]], - private val signalHandlers: List[ReceiveBuilder.Case[T, Signal]] + messageHandlers: List[ReceiveBuilder.Case[T, T]], + signalHandlers: List[ReceiveBuilder.Case[T, Signal]] ) extends Receive[T] { import ReceiveBuilder.Case @@ -159,7 +168,7 @@ private final class BuiltReceive[T]( private def receive[M](msg: M, handlers: List[Case[T, M]]): Behavior[T] = handlers match { case Case(cls, predicate, handler) :: tail ⇒ - if (cls.isAssignableFrom(msg.getClass) && (predicate.isEmpty || predicate.get.apply(msg))) handler(msg) + if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.test(msg))) handler(msg) else receive[M](msg, tail) case _ ⇒ Behaviors.unhandled diff --git a/akka-actor/src/main/scala/akka/japi/function/Function.scala b/akka-actor/src/main/scala/akka/japi/function/Function.scala index 779702882d..b9fc23d0c5 100644 --- a/akka-actor/src/main/scala/akka/japi/function/Function.scala +++ b/akka-actor/src/main/scala/akka/japi/function/Function.scala @@ -7,6 +7,7 @@ package akka.japi.function /** * A Function interface. Used to create first-class-functions is Java. * `Serializable` is needed to be able to grab line number for Java 8 lambdas. + * Supports throwing `Exception` in the apply, which the `java.util.function.Function` counterpart does not. */ @SerialVersionUID(1L) trait Function[-T, +R] extends java.io.Serializable { @@ -17,6 +18,7 @@ trait Function[-T, +R] extends java.io.Serializable { /** * A Function interface. Used to create 2-arg first-class-functions is Java. * `Serializable` is needed to be able to grab line number for Java 8 lambdas. + * Supports throwing `Exception` in the apply, which the `java.util.function.BiFunction` counterpart does not. */ @SerialVersionUID(1L) trait Function2[-T1, -T2, +R] extends java.io.Serializable { @@ -27,6 +29,7 @@ trait Function2[-T1, -T2, +R] extends java.io.Serializable { /** * A Procedure is like a Function, but it doesn't produce a return value. * `Serializable` is needed to be able to grab line number for Java 8 lambdas. + * Supports throwing `Exception` in the apply, which the `java.util.function.Consumer` counterpart does not. */ @SerialVersionUID(1L) trait Procedure[-T] extends java.io.Serializable { @@ -37,9 +40,11 @@ trait Procedure[-T] extends java.io.Serializable { /** * An executable piece of code that takes no parameters and doesn't return any value. * `Serializable` is needed to be able to grab line number for Java 8 lambdas. + * Supports throwing `Exception` in the apply, which the `java.util.function.Effect` counterpart does not. */ @SerialVersionUID(1L) trait Effect extends java.io.Serializable { + @throws(classOf[Exception]) def apply(): Unit } @@ -47,6 +52,7 @@ trait Effect extends java.io.Serializable { /** * Java API: Defines a criteria and determines whether the parameter meets this criteria. * `Serializable` is needed to be able to grab line number for Java 8 lambdas. + * Supports throwing `Exception` in the apply, which the `java.util.function.Predicate` counterpart does not. */ @SerialVersionUID(1L) trait Predicate[-T] extends java.io.Serializable { @@ -55,6 +61,7 @@ trait Predicate[-T] extends java.io.Serializable { /** * A constructor/factory, takes no parameters but creates a new value of type T every call. + * Supports throwing `Exception` in the apply, which the `java.util.function.Creator` counterpart does not. */ @SerialVersionUID(1L) trait Creator[+T] extends Serializable { diff --git a/akka-cluster-typed/src/test/java/akka/cluster/ddata/typed/javadsl/ReplicatorTest.java b/akka-cluster-typed/src/test/java/akka/cluster/ddata/typed/javadsl/ReplicatorTest.java index 58c24b8913..d3f670e896 100644 --- a/akka-cluster-typed/src/test/java/akka/cluster/ddata/typed/javadsl/ReplicatorTest.java +++ b/akka-cluster-typed/src/test/java/akka/cluster/ddata/typed/javadsl/ReplicatorTest.java @@ -134,7 +134,7 @@ public class ReplicatorTest extends JUnitSuite { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(Increment.class, this::onIncrement) .onMessage(InternalUpdateResponse.class, msg -> Behaviors.same()) .onMessage(GetValue.class, this::onGetValue) diff --git a/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/ReceptionistExampleTest.java b/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/ReceptionistExampleTest.java index ad42219bfb..0789b9a828 100644 --- a/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/ReceptionistExampleTest.java +++ b/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/ReceptionistExampleTest.java @@ -50,7 +50,7 @@ public class ReceptionistExampleTest extends JUnitSuite { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage( Receptionist.Listing.class, listing -> listing.isForKey(serviceKey), @@ -131,7 +131,7 @@ public class ReceptionistExampleTest extends JUnitSuite { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage( Receptionist.Listing.class, listing -> listing.isForKey(serviceKey), diff --git a/akka-docs/src/main/paradox/typed/actors.md b/akka-docs/src/main/paradox/typed/actors.md index b6e7e971ab..2881c3d4a1 100644 --- a/akka-docs/src/main/paradox/typed/actors.md +++ b/akka-docs/src/main/paradox/typed/actors.md @@ -141,7 +141,7 @@ The console output may look like this: The next example is more realistic and demonstrates some important patterns: -* Using a sealed trait and case class/objects to represent multiple messages an actor can receive +* Using @scala[a sealed trait and case class/objects]@java[an interface and classes implementing that interface] to represent multiple messages an actor can receive * Handle sessions by using child actors * Handling state by changing behavior * Using multiple typed actors to represent different parts of a protocol in a type safe way @@ -357,6 +357,10 @@ As the state is mutable, we never return a different behavior from the message l the `AbstractBehavior` instance itself (`this`) as a behavior to use for processing the next message coming in. We could also return `Behavior.same` to achieve the same. +@java[In this sample we make separate statements for creating the behavior builder, but it also returns the builder +itself from each step so a more fluent behavior definition style is also possible. What you should prefer depends on +how big the set of messages the actor accepts is.] + It is also possible to return a new different `AbstractBehavior`, for example to represent a different state in a finite state machine (FSM), or use one of the functional behavior factories to combine the object oriented with the functional style for different parts of the lifecycle of the same Actor behavior. diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_1/ActorHierarchyExperiments.java b/akka-docs/src/test/java/jdocs/typed/tutorial_1/ActorHierarchyExperiments.java index bf39fab7cb..291e289a73 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_1/ActorHierarchyExperiments.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_1/ActorHierarchyExperiments.java @@ -36,7 +36,7 @@ class PrintMyActorRefActor extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder().onMessageEquals("printit", this::printIt).build(); + return newReceiveBuilder().onMessageEquals("printit", this::printIt).build(); } private Behavior printIt() { @@ -60,7 +60,7 @@ class StartStopActor1 extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessageEquals("stop", Behaviors::stopped) .onSignal(PostStop.class, signal -> postStop()) .build(); @@ -84,7 +84,7 @@ class StartStopActor2 extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder().onSignal(PostStop.class, signal -> postStop()).build(); + return newReceiveBuilder().onSignal(PostStop.class, signal -> postStop()).build(); } private Behavior postStop() { @@ -113,7 +113,7 @@ class SupervisingActor extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder().onMessageEquals("failChild", this::failChild).build(); + return newReceiveBuilder().onMessageEquals("failChild", this::failChild).build(); } private Behavior failChild() { @@ -134,7 +134,7 @@ class SupervisedActor extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessageEquals("fail", this::fail) .onSignal(PreRestart.class, signal -> preRestart()) .onSignal(PostStop.class, signal -> postStop()) @@ -174,7 +174,7 @@ class Main extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder().onMessageEquals("start", this::start).build(); + return newReceiveBuilder().onMessageEquals("start", this::start).build(); } private Behavior start() { diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_2/IotSupervisor.java b/akka-docs/src/test/java/jdocs/typed/tutorial_2/IotSupervisor.java index 900124410c..c0b9907f5c 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_2/IotSupervisor.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_2/IotSupervisor.java @@ -28,7 +28,7 @@ public class IotSupervisor extends AbstractBehavior { // No need to handle any messages @Override public Receive createReceive() { - return receiveBuilder().onSignal(PostStop.class, signal -> postStop()).build(); + return newReceiveBuilder().onSignal(PostStop.class, signal -> postStop()).build(); } private IotSupervisor postStop() { diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_3/Device.java b/akka-docs/src/test/java/jdocs/typed/tutorial_3/Device.java index 5f868ce5ce..a22589583b 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_3/Device.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_3/Device.java @@ -46,7 +46,7 @@ public class Device extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(RecordTemperature.class, this::recordTemperature) .onMessage(ReadTemperature.class, this::readTemperature) .onSignal(PostStop.class, signal -> postStop()) diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_3/inprogress2/Device.java b/akka-docs/src/test/java/jdocs/typed/tutorial_3/inprogress2/Device.java index f4a8631322..dc451ac8f0 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_3/inprogress2/Device.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_3/inprogress2/Device.java @@ -46,7 +46,7 @@ public class Device extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(ReadTemperature.class, this::readTemperature) .onSignal(PostStop.class, signal -> postStop()) .build(); diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_4/Device.java b/akka-docs/src/test/java/jdocs/typed/tutorial_4/Device.java index 6f78531a7c..ae4fa714d5 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_4/Device.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_4/Device.java @@ -46,7 +46,7 @@ public class Device extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(RecordTemperature.class, this::recordTemperature) .onMessage(ReadTemperature.class, this::readTemperature) .onMessage(Passivate.class, m -> Behaviors.stopped()) diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceGroup.java b/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceGroup.java index d90b7768df..5285e09d97 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceGroup.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceGroup.java @@ -98,7 +98,7 @@ public class DeviceGroup extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(RequestTrackDevice.class, this::onTrackDevice) // #device-group-register // #device-group-remove diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceManager.java b/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceManager.java index de416e5ed8..eb024f1fad 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceManager.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_4/DeviceManager.java @@ -74,7 +74,7 @@ public class DeviceManager extends AbstractBehavior { } public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(RequestTrackDevice.class, this::onTrackDevice) .onMessage(RequestDeviceList.class, this::onRequestDeviceList) .onMessage(DeviceGroupTerminated.class, this::onTerminated) diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_5/Device.java b/akka-docs/src/test/java/jdocs/typed/tutorial_5/Device.java index 76846d8e63..824ebecf14 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_5/Device.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_5/Device.java @@ -37,7 +37,7 @@ public class Device extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(RecordTemperature.class, this::recordTemperature) .onMessage(ReadTemperature.class, this::readTemperature) .onMessage(Passivate.class, m -> Behaviors.stopped()) diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroup.java b/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroup.java index 047830a051..ecd36b007b 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroup.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroup.java @@ -113,7 +113,7 @@ public class DeviceGroup extends AbstractBehavior { @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() // #query-added .onMessage(RequestTrackDevice.class, this::onTrackDevice) .onMessage(RequestDeviceList.class, r -> r.groupId.equals(groupId), this::onDeviceList) diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroupQuery.java b/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroupQuery.java index 56e2fed6e8..a5bfe82441 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroupQuery.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceGroupQuery.java @@ -95,7 +95,7 @@ public class DeviceGroupQuery extends AbstractBehavior // #query-state @Override public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(WrappedRespondTemperature.class, this::onRespondTemperature) .onMessage(DeviceTerminated.class, this::onDeviceTerminated) .onMessage(CollectionTimeout.class, this::onCollectionTimeout) diff --git a/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceManager.java b/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceManager.java index a49765835c..8ab7c876ed 100644 --- a/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceManager.java +++ b/akka-docs/src/test/java/jdocs/typed/tutorial_5/DeviceManager.java @@ -83,7 +83,7 @@ public class DeviceManager extends AbstractBehavior { } public Receive createReceive() { - return receiveBuilder() + return newReceiveBuilder() .onMessage(RequestTrackDevice.class, this::onTrackDevice) .onMessage(RequestDeviceList.class, this::onRequestDeviceList) .onMessage(RequestAllTemperatures.class, this::onRequestAllTemperatures)