示例#1
0
public class FlowThrottleTest extends StreamTest {
  public FlowThrottleTest() {
    super(actorSystemResource);
  }

  @ClassRule
  public static AkkaJUnitActorSystemResource actorSystemResource =
      new AkkaJUnitActorSystemResource("ThrottleTest", AkkaSpec.testConf());

  @Test
  public void mustWorksForTwoStreams() throws Exception {
    final Flow<Integer, Integer, NotUsed> sharedThrottle =
        Flow.of(Integer.class)
            .throttle(1, FiniteDuration.create(1, TimeUnit.DAYS), 1, ThrottleMode.enforcing());

    CompletionStage<List<Integer>> result1 =
        Source.single(1).via(sharedThrottle).via(sharedThrottle).runWith(Sink.seq(), materializer);

    // If there is accidental shared state then we would not be able to pass through the single
    // element
    assertEquals(
        result1.toCompletableFuture().get(3, TimeUnit.SECONDS), Collections.singletonList(1));

    // It works with a new stream, too
    CompletionStage<List<Integer>> result2 =
        Source.single(1).via(sharedThrottle).via(sharedThrottle).runWith(Sink.seq(), materializer);

    assertEquals(
        result2.toCompletableFuture().get(3, TimeUnit.SECONDS), Collections.singletonList(1));
  }
}
示例#2
0
/** Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com> */
public class PatternsTest {

  @ClassRule
  public static AkkaJUnitActorSystemResource actorSystemResource =
      new AkkaJUnitActorSystemResource("JavaAPI", AkkaSpec.testConf());

  private final ActorSystem system = actorSystemResource.getSystem();

  @Test
  public void useAsk() throws Exception {
    ActorRef testActor = system.actorOf(Props.create(JavaAPITestActor.class), "test");
    assertEquals(
        "Ask should return expected answer",
        JavaAPITestActor.ANSWER,
        Await.result(ask(testActor, "hey!", 3000), Duration.create(3, "seconds")));
  }

  @Test
  public void useAskWithActorSelection() throws Exception {
    ActorRef testActor = system.actorOf(Props.create(JavaAPITestActor.class), "test2");
    ActorSelection selection = system.actorSelection("/user/test2");
    ActorIdentity id =
        (ActorIdentity)
            Await.result(ask(selection, new Identify("yo!"), 3000), Duration.create(3, "seconds"));
    assertEquals("Ask (Identify) should return the proper ActorIdentity", testActor, id.getRef());
  }

  @Test
  public void usePipe() throws Exception {
    TestProbe probe = new TestProbe(system);
    pipe(Futures.successful("ho!"), system.dispatcher()).to(probe.ref());
    probe.expectMsg("ho!");
  }

  @Test
  public void usePipeWithActorSelection() throws Exception {
    TestProbe probe = new TestProbe(system);
    ActorSelection selection = system.actorSelection(probe.ref().path());
    pipe(Futures.successful("hi!"), system.dispatcher()).to(selection);
    probe.expectMsg("hi!");
  }
}
  public static void main(String[] args) throws InterruptedException {

    ActorSystem app = ActorSystem.create("UntypedCoordinatedExample", AkkaSpec.testConf());

    ActorRef counter1 = app.actorOf(new Props().withCreator(UntypedCoordinatedCounter.class));
    ActorRef counter2 = app.actorOf(new Props().withCreator(UntypedCoordinatedCounter.class));

    counter1.tell(new Coordinated(new Increment(counter2)));

    Thread.sleep(3000);

    long timeout = 5000;
    Duration d = Duration.create(timeout, TimeUnit.MILLISECONDS);

    Future<Object> future1 = counter1.ask("GetCount", timeout);
    Future<Object> future2 = counter2.ask("GetCount", timeout);

    int count1 = (Integer) Await.result(future1, d);
    System.out.println("counter 1: " + count1);
    int count2 = (Integer) Await.result(future2, d);
    System.out.println("counter 1: " + count2);

    app.shutdown();
  }
示例#4
0
 @BeforeClass
 public static void beforeAll() {
   system = ActorSystem.create("JavaFutureTests", AkkaSpec.testConf());
   t = TestKitExtension.get(system).DefaultTimeout();
 }
 @Before
 public void setUp() {
   system = ActorSystem.create("MySystem", AkkaSpec.testConf());
 }
示例#6
0
 @BeforeClass
 public static void setUp() {
   system = ActorSystem.create("SchedulerPatternTest", AkkaSpec.testConf());
 }
示例#7
0
@SuppressWarnings("serial")
public class SourceTest extends StreamTest {
  public SourceTest() {
    super(actorSystemResource);
  }

  @ClassRule
  public static AkkaJUnitActorSystemResource actorSystemResource =
      new AkkaJUnitActorSystemResource("SourceTest", AkkaSpec.testConf());

  @Test
  public void mustBeAbleToUseSimpleOperators() {
    final JavaTestKit probe = new JavaTestKit(system);
    final String[] lookup = {"a", "b", "c", "d", "e", "f"};
    final java.lang.Iterable<Integer> input = Arrays.asList(0, 1, 2, 3, 4, 5);
    final Source<Integer, NotUsed> ints = Source.from(input);

    ints.drop(2)
        .take(3)
        .takeWithin(FiniteDuration.create(10, TimeUnit.SECONDS))
        .map(elem -> lookup[elem])
        .filter(elem -> !elem.equals("c"))
        .grouped(2)
        .mapConcat(elem -> elem)
        .groupedWithin(100, FiniteDuration.create(50, TimeUnit.MILLISECONDS))
        .mapConcat(elem -> elem)
        .runFold("", (acc, elem) -> acc + elem, materializer)
        .thenAccept(elem -> probe.getRef().tell(elem, ActorRef.noSender()));

    probe.expectMsgEquals("de");
  }

  @Test
  public void mustBeAbleToUseVoidTypeInForeach() {
    final JavaTestKit probe = new JavaTestKit(system);
    final java.lang.Iterable<String> input = Arrays.asList("a", "b", "c");
    Source<String, NotUsed> ints = Source.from(input);

    final CompletionStage<Done> completion =
        ints.runForeach(elem -> probe.getRef().tell(elem, ActorRef.noSender()), materializer);

    completion.thenAccept(elem -> probe.getRef().tell(String.valueOf(elem), ActorRef.noSender()));

    probe.expectMsgEquals("a");
    probe.expectMsgEquals("b");
    probe.expectMsgEquals("c");
    probe.expectMsgEquals("Done");
  }

  @Ignore("StatefulStage to be converted to GraphStage when Java Api is available (#18817)")
  @Test
  public void mustBeAbleToUseTransform() {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<Integer> input = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7);
    // duplicate each element, stop after 4 elements, and emit sum to the end
    Source.from(input)
        .transform(
            new Creator<Stage<Integer, Integer>>() {
              @Override
              public PushPullStage<Integer, Integer> create() throws Exception {
                return new StatefulStage<Integer, Integer>() {
                  int sum = 0;
                  int count = 0;

                  @Override
                  public StageState<Integer, Integer> initial() {
                    return new StageState<Integer, Integer>() {
                      @Override
                      public SyncDirective onPush(Integer element, Context<Integer> ctx) {
                        sum += element;
                        count += 1;
                        if (count == 4) {
                          return emitAndFinish(
                              Arrays.asList(element, element, sum).iterator(), ctx);
                        } else {
                          return emit(Arrays.asList(element, element).iterator(), ctx);
                        }
                      }
                    };
                  }

                  @Override
                  public TerminationDirective onUpstreamFinish(Context<Integer> ctx) {
                    return terminationEmit(Collections.singletonList(sum).iterator(), ctx);
                  }
                };
              }
            })
        .runForeach(
            new Procedure<Integer>() {
              public void apply(Integer elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    probe.expectMsgEquals(0);
    probe.expectMsgEquals(0);
    probe.expectMsgEquals(1);
    probe.expectMsgEquals(1);
    probe.expectMsgEquals(2);
    probe.expectMsgEquals(2);
    probe.expectMsgEquals(3);
    probe.expectMsgEquals(3);
    probe.expectMsgEquals(6);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void mustBeAbleToUseGroupBy() throws Exception {
    final Iterable<String> input = Arrays.asList("Aaa", "Abb", "Bcc", "Cdd", "Cee");
    final Source<List<String>, NotUsed> source =
        Source.from(input)
            .groupBy(
                3,
                new Function<String, String>() {
                  public String apply(String elem) {
                    return elem.substring(0, 1);
                  }
                })
            .grouped(10)
            .mergeSubstreams();

    final CompletionStage<List<List<String>>> future =
        source.grouped(10).runWith(Sink.<List<List<String>>>head(), materializer);
    final Object[] result = future.toCompletableFuture().get(1, TimeUnit.SECONDS).toArray();
    Arrays.sort(
        result,
        (Comparator<Object>)
            (Object)
                new Comparator<List<String>>() {
                  @Override
                  public int compare(List<String> o1, List<String> o2) {
                    return o1.get(0).charAt(0) - o2.get(0).charAt(0);
                  }
                });

    assertArrayEquals(
        new Object[] {
          Arrays.asList("Aaa", "Abb"), Arrays.asList("Bcc"), Arrays.asList("Cdd", "Cee")
        },
        result);
  }

  @Test
  public void mustBeAbleToUseSplitWhen() throws Exception {
    final Iterable<String> input = Arrays.asList("A", "B", "C", ".", "D", ".", "E", "F");
    final Source<List<String>, NotUsed> source =
        Source.from(input)
            .splitWhen(
                new Predicate<String>() {
                  public boolean test(String elem) {
                    return elem.equals(".");
                  }
                })
            .grouped(10)
            .concatSubstreams();

    final CompletionStage<List<List<String>>> future =
        source.grouped(10).runWith(Sink.<List<List<String>>>head(), materializer);
    final List<List<String>> result = future.toCompletableFuture().get(1, TimeUnit.SECONDS);

    assertEquals(
        Arrays.asList(
            Arrays.asList("A", "B", "C"), Arrays.asList(".", "D"), Arrays.asList(".", "E", "F")),
        result);
  }

  @Test
  public void mustBeAbleToUseSplitAfter() throws Exception {
    final Iterable<String> input = Arrays.asList("A", "B", "C", ".", "D", ".", "E", "F");
    final Source<List<String>, NotUsed> source =
        Source.from(input)
            .splitAfter(
                new Predicate<String>() {
                  public boolean test(String elem) {
                    return elem.equals(".");
                  }
                })
            .grouped(10)
            .concatSubstreams();

    final CompletionStage<List<List<String>>> future =
        source.grouped(10).runWith(Sink.<List<List<String>>>head(), materializer);
    final List<List<String>> result = future.toCompletableFuture().get(1, TimeUnit.SECONDS);

    assertEquals(
        Arrays.asList(
            Arrays.asList("A", "B", "C", "."), Arrays.asList("D", "."), Arrays.asList("E", "F")),
        result);
  }

  @Test
  public void mustBeAbleToUseConcat() {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input1 = Arrays.asList("A", "B", "C");
    final Iterable<String> input2 = Arrays.asList("D", "E", "F");

    final Source<String, NotUsed> in1 = Source.from(input1);
    final Source<String, NotUsed> in2 = Source.from(input2);

    in1.concat(in2)
        .runForeach(
            new Procedure<String>() {
              public void apply(String elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    List<Object> output = Arrays.asList(probe.receiveN(6));
    assertEquals(Arrays.asList("A", "B", "C", "D", "E", "F"), output);
  }

  @Test
  public void mustBeAbleToUsePrepend() {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input1 = Arrays.asList("A", "B", "C");
    final Iterable<String> input2 = Arrays.asList("D", "E", "F");

    final Source<String, NotUsed> in1 = Source.from(input1);
    final Source<String, NotUsed> in2 = Source.from(input2);

    in2.prepend(in1)
        .runForeach(
            new Procedure<String>() {
              public void apply(String elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    List<Object> output = Arrays.asList(probe.receiveN(6));
    assertEquals(Arrays.asList("A", "B", "C", "D", "E", "F"), output);
  }

  @Test
  public void mustBeAbleToUseCallableInput() {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<Integer> input1 = Arrays.asList(4, 3, 2, 1, 0);
    final Creator<Iterator<Integer>> input =
        new Creator<Iterator<Integer>>() {
          @Override
          public Iterator<Integer> create() {
            return input1.iterator();
          }
        };
    Source.fromIterator(input)
        .runForeach(
            new Procedure<Integer>() {
              public void apply(Integer elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    List<Object> output = Arrays.asList(probe.receiveN(5));
    assertEquals(Arrays.asList(4, 3, 2, 1, 0), output);
    probe.expectNoMsg(FiniteDuration.create(500, TimeUnit.MILLISECONDS));
  }

  @Test
  public void mustBeAbleToUseOnCompleteSuccess() {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input = Arrays.asList("A", "B", "C");

    Source.from(input)
        .runWith(
            Sink.<String>onComplete(
                new Procedure<Try<Done>>() {
                  @Override
                  public void apply(Try<Done> param) throws Exception {
                    probe.getRef().tell(param.get(), ActorRef.noSender());
                  }
                }),
            materializer);

    probe.expectMsgClass(Done.class);
  }

  @Test
  public void mustBeAbleToUseOnCompleteError() {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input = Arrays.asList("A", "B", "C");

    Source.from(input)
        .<String>map(
            in -> {
              throw new RuntimeException("simulated err");
            })
        .runWith(Sink.<String>head(), materializer)
        .whenComplete(
            (s, ex) -> {
              if (ex == null) {
                probe.getRef().tell("done", ActorRef.noSender());
              } else {
                probe.getRef().tell(ex.getMessage(), ActorRef.noSender());
              }
            });

    probe.expectMsgEquals("simulated err");
  }

  @Test
  public void mustBeAbleToUseToFuture() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input = Arrays.asList("A", "B", "C");
    CompletionStage<String> future = Source.from(input).runWith(Sink.<String>head(), materializer);
    String result = future.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals("A", result);
  }

  @Test
  public void mustBeAbleToUsePrefixAndTail() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<Integer> input = Arrays.asList(1, 2, 3, 4, 5, 6);
    CompletionStage<Pair<List<Integer>, Source<Integer, NotUsed>>> future =
        Source.from(input)
            .prefixAndTail(3)
            .runWith(Sink.<Pair<List<Integer>, Source<Integer, NotUsed>>>head(), materializer);
    Pair<List<Integer>, Source<Integer, NotUsed>> result =
        future.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals(Arrays.asList(1, 2, 3), result.first());

    CompletionStage<List<Integer>> tailFuture =
        result.second().limit(4).runWith(Sink.<Integer>seq(), materializer);
    List<Integer> tailResult = tailFuture.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals(Arrays.asList(4, 5, 6), tailResult);
  }

  @Test
  public void mustBeAbleToUseConcatAllWithSources() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<Integer> input1 = Arrays.asList(1, 2, 3);
    final Iterable<Integer> input2 = Arrays.asList(4, 5);

    final List<Source<Integer, NotUsed>> mainInputs = new ArrayList<Source<Integer, NotUsed>>();
    mainInputs.add(Source.from(input1));
    mainInputs.add(Source.from(input2));

    CompletionStage<List<Integer>> future =
        Source.from(mainInputs)
            .<Integer, NotUsed>flatMapConcat(
                ConstantFun.<Source<Integer, NotUsed>>javaIdentityFunction())
            .grouped(6)
            .runWith(Sink.<List<Integer>>head(), materializer);

    List<Integer> result = future.toCompletableFuture().get(3, TimeUnit.SECONDS);

    assertEquals(Arrays.asList(1, 2, 3, 4, 5), result);
  }

  @Test
  public void mustBeAbleToUseFlatMapMerge() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<Integer> input1 = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    final Iterable<Integer> input2 = Arrays.asList(10, 11, 12, 13, 14, 15, 16, 17, 18, 19);
    final Iterable<Integer> input3 = Arrays.asList(20, 21, 22, 23, 24, 25, 26, 27, 28, 29);
    final Iterable<Integer> input4 = Arrays.asList(30, 31, 32, 33, 34, 35, 36, 37, 38, 39);

    final List<Source<Integer, NotUsed>> mainInputs = new ArrayList<Source<Integer, NotUsed>>();
    mainInputs.add(Source.from(input1));
    mainInputs.add(Source.from(input2));
    mainInputs.add(Source.from(input3));
    mainInputs.add(Source.from(input4));

    CompletionStage<List<Integer>> future =
        Source.from(mainInputs)
            .flatMapMerge(3, ConstantFun.<Source<Integer, NotUsed>>javaIdentityFunction())
            .grouped(60)
            .runWith(Sink.<List<Integer>>head(), materializer);

    List<Integer> result = future.toCompletableFuture().get(3, TimeUnit.SECONDS);
    final Set<Integer> set = new HashSet<Integer>();
    for (Integer i : result) {
      set.add(i);
    }
    final Set<Integer> expected = new HashSet<Integer>();
    for (int i = 0; i < 40; ++i) {
      expected.add(i);
    }

    assertEquals(expected, set);
  }

  @Test
  public void mustBeAbleToUseBuffer() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final List<String> input = Arrays.asList("A", "B", "C");
    final CompletionStage<List<String>> future =
        Source.from(input)
            .buffer(2, OverflowStrategy.backpressure())
            .grouped(4)
            .runWith(Sink.<List<String>>head(), materializer);

    List<String> result = future.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals(input, result);
  }

  @Test
  public void mustBeAbleToUseConflate() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final List<String> input = Arrays.asList("A", "B", "C");
    CompletionStage<String> future =
        Source.from(input)
            .conflateWithSeed(s -> s, (aggr, in) -> aggr + in)
            .runFold("", (aggr, in) -> aggr + in, materializer);
    String result = future.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals("ABC", result);

    final Flow<String, String, NotUsed> flow2 = Flow.of(String.class).conflate((a, b) -> a + b);

    CompletionStage<String> future2 =
        Source.from(input)
            .conflate((String a, String b) -> a + b)
            .runFold("", (a, b) -> a + b, materializer);
    String result2 = future2.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals("ABC", result2);
  }

  @Test
  public void mustBeAbleToUseExpand() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final List<String> input = Arrays.asList("A", "B", "C");
    CompletionStage<String> future =
        Source.from(input)
            .expand(in -> Stream.iterate(in, i -> i).iterator())
            .runWith(Sink.<String>head(), materializer);
    String result = future.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals("A", result);
  }

  @Test
  public void mustProduceTicks() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    Source<String, Cancellable> tickSource =
        Source.tick(
            FiniteDuration.create(1, TimeUnit.SECONDS),
            FiniteDuration.create(500, TimeUnit.MILLISECONDS),
            "tick");
    @SuppressWarnings("unused")
    Cancellable cancellable =
        tickSource
            .to(
                Sink.foreach(
                    new Procedure<String>() {
                      public void apply(String elem) {
                        probe.getRef().tell(elem, ActorRef.noSender());
                      }
                    }))
            .run(materializer);
    probe.expectNoMsg(FiniteDuration.create(600, TimeUnit.MILLISECONDS));
    probe.expectMsgEquals("tick");
    probe.expectNoMsg(FiniteDuration.create(200, TimeUnit.MILLISECONDS));
    probe.expectMsgEquals("tick");
    probe.expectNoMsg(FiniteDuration.create(200, TimeUnit.MILLISECONDS));
  }

  @Test
  public void mustBeAbleToUseMapFuture() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input = Arrays.asList("a", "b", "c");
    Source.from(input)
        .mapAsync(4, elem -> CompletableFuture.completedFuture(elem.toUpperCase()))
        .runForeach(elem -> probe.getRef().tell(elem, ActorRef.noSender()), materializer);
    probe.expectMsgEquals("A");
    probe.expectMsgEquals("B");
    probe.expectMsgEquals("C");
  }

  @Test
  public void mustWorkFromFuture() throws Exception {
    final Iterable<String> input = Arrays.asList("A", "B", "C");
    CompletionStage<String> future1 = Source.from(input).runWith(Sink.<String>head(), materializer);
    CompletionStage<String> future2 =
        Source.fromCompletionStage(future1).runWith(Sink.<String>head(), materializer);
    String result = future2.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals("A", result);
  }

  @Test
  public void mustWorkFromRange() throws Exception {
    CompletionStage<List<Integer>> f =
        Source.range(0, 10).grouped(20).runWith(Sink.<List<Integer>>head(), materializer);
    final List<Integer> result = f.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals(11, result.size());
    Integer counter = 0;
    for (Integer i : result) assertEquals(i, counter++);
  }

  @Test
  public void mustWorkFromRangeWithStep() throws Exception {
    CompletionStage<List<Integer>> f =
        Source.range(0, 10, 2).grouped(20).runWith(Sink.<List<Integer>>head(), materializer);
    final List<Integer> result = f.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals(6, result.size());
    Integer counter = 0;
    for (Integer i : result) {
      assertEquals(i, counter);
      counter += 2;
    }
  }

  @Test
  public void mustRepeat() throws Exception {
    final CompletionStage<List<Integer>> f =
        Source.repeat(42).grouped(10000).runWith(Sink.<List<Integer>>head(), materializer);
    final List<Integer> result = f.toCompletableFuture().get(3, TimeUnit.SECONDS);
    assertEquals(result.size(), 10000);
    for (Integer i : result) assertEquals(i, (Integer) 42);
  }

  @Test
  public void mustBeAbleToUseQueue() throws Exception {
    final Pair<SourceQueueWithComplete<String>, CompletionStage<List<String>>> x =
        Flow.of(String.class)
            .runWith(Source.queue(2, OverflowStrategy.fail()), Sink.seq(), materializer);
    final SourceQueueWithComplete<String> source = x.first();
    final CompletionStage<List<String>> result = x.second();
    source.offer("hello");
    source.offer("world");
    source.complete();
    assertEquals(
        result.toCompletableFuture().get(3, TimeUnit.SECONDS), Arrays.asList("hello", "world"));
  }

  @Test
  public void mustBeAbleToUseActorRefSource() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Source<Integer, ActorRef> actorRefSource = Source.actorRef(10, OverflowStrategy.fail());
    final ActorRef ref =
        actorRefSource
            .to(
                Sink.foreach(
                    new Procedure<Integer>() {
                      public void apply(Integer elem) {
                        probe.getRef().tell(elem, ActorRef.noSender());
                      }
                    }))
            .run(materializer);
    ref.tell(1, ActorRef.noSender());
    probe.expectMsgEquals(1);
    ref.tell(2, ActorRef.noSender());
    probe.expectMsgEquals(2);
  }

  @Test
  public void mustBeAbleToUseStatefulMaponcat() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final java.lang.Iterable<Integer> input = Arrays.asList(1, 2, 3, 4, 5);
    final Source<Integer, NotUsed> ints =
        Source.from(input)
            .statefulMapConcat(
                () -> {
                  int[] state = new int[] {0};
                  return (elem) -> {
                    List<Integer> list = new ArrayList<>(Collections.nCopies(state[0], elem));
                    state[0] = elem;
                    return list;
                  };
                });

    ints.runFold("", (acc, elem) -> acc + elem, materializer)
        .thenAccept(elem -> probe.getRef().tell(elem, ActorRef.noSender()));

    probe.expectMsgEquals("2334445555");
  }

  @Test
  public void mustBeAbleToUseIntersperse() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Source<String, NotUsed> source =
        Source.from(Arrays.asList("0", "1", "2", "3")).intersperse("[", ",", "]");

    final CompletionStage<Done> future =
        source.runWith(
            Sink.foreach(elem -> probe.getRef().tell(elem, ActorRef.noSender())), materializer);

    probe.expectMsgEquals("[");
    probe.expectMsgEquals("0");
    probe.expectMsgEquals(",");
    probe.expectMsgEquals("1");
    probe.expectMsgEquals(",");
    probe.expectMsgEquals("2");
    probe.expectMsgEquals(",");
    probe.expectMsgEquals("3");
    probe.expectMsgEquals("]");
    future.toCompletableFuture().get(200, TimeUnit.MILLISECONDS);
  }

  @Test
  public void mustBeAbleToUseIntersperseAndConcat() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Source<String, NotUsed> source =
        Source.from(Arrays.asList("0", "1", "2", "3")).intersperse(",");

    final CompletionStage<Done> future =
        Source.single(">> ")
            .concat(source)
            .runWith(
                Sink.foreach(elem -> probe.getRef().tell(elem, ActorRef.noSender())), materializer);

    probe.expectMsgEquals(">> ");
    probe.expectMsgEquals("0");
    probe.expectMsgEquals(",");
    probe.expectMsgEquals("1");
    probe.expectMsgEquals(",");
    probe.expectMsgEquals("2");
    probe.expectMsgEquals(",");
    probe.expectMsgEquals("3");
    future.toCompletableFuture().get(200, TimeUnit.MILLISECONDS);
  }

  @Test
  public void mustBeAbleToUseDropWhile() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Source<Integer, NotUsed> source =
        Source.from(Arrays.asList(0, 1, 2, 3))
            .dropWhile(
                new Predicate<Integer>() {
                  public boolean test(Integer elem) {
                    return elem < 2;
                  }
                });

    final CompletionStage<Done> future =
        source.runWith(
            Sink.foreach(elem -> probe.getRef().tell(elem, ActorRef.noSender())), materializer);

    probe.expectMsgEquals(2);
    probe.expectMsgEquals(3);
    future.toCompletableFuture().get(200, TimeUnit.MILLISECONDS);
  }

  @Test
  public void mustBeAbleToUseTakeWhile() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Source<Integer, NotUsed> source =
        Source.from(Arrays.asList(0, 1, 2, 3))
            .takeWhile(
                new Predicate<Integer>() {
                  public boolean test(Integer elem) {
                    return elem < 2;
                  }
                });

    final CompletionStage<Done> future =
        source.runWith(
            Sink.foreach(elem -> probe.getRef().tell(elem, ActorRef.noSender())), materializer);

    probe.expectMsgEquals(0);
    probe.expectMsgEquals(1);

    FiniteDuration duration = Duration.apply(200, TimeUnit.MILLISECONDS);

    probe.expectNoMsg(duration);
    future.toCompletableFuture().get(200, TimeUnit.MILLISECONDS);
  }

  @Test
  public void mustBeAbleToRecover() throws Exception {
    final ManualProbe<Integer> publisherProbe = TestPublisher.manualProbe(true, system);
    final JavaTestKit probe = new JavaTestKit(system);

    final Source<Integer, NotUsed> source =
        Source.fromPublisher(publisherProbe)
            .map(
                elem -> {
                  if (elem == 1) throw new RuntimeException("ex");
                  else return elem;
                })
            .recover(new PFBuilder<Throwable, Integer>().matchAny(ex -> 0).build());

    final CompletionStage<Done> future =
        source.runWith(
            Sink.foreach(elem -> probe.getRef().tell(elem, ActorRef.noSender())), materializer);
    final PublisherProbeSubscription<Integer> s = publisherProbe.expectSubscription();
    s.sendNext(0);
    probe.expectMsgEquals(0);
    s.sendNext(1);
    probe.expectMsgEquals(0);

    future.toCompletableFuture().get(200, TimeUnit.MILLISECONDS);
  }

  @Test
  public void mustBeAbleToCombine() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Source<Integer, NotUsed> source1 = Source.from(Arrays.asList(0, 1));
    final Source<Integer, NotUsed> source2 = Source.from(Arrays.asList(2, 3));

    final Source<Integer, NotUsed> source =
        Source.combine(
            source1,
            source2,
            new ArrayList<Source<Integer, ?>>(),
            width -> Merge.<Integer>create(width));

    final CompletionStage<Done> future =
        source.runWith(
            Sink.foreach(elem -> probe.getRef().tell(elem, ActorRef.noSender())), materializer);

    probe.expectMsgAllOf(0, 1, 2, 3);

    future.toCompletableFuture().get(200, TimeUnit.MILLISECONDS);
  }

  @Test
  public void mustBeAbleToUseMerge() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input1 = Arrays.asList("A", "B", "C");
    final Iterable<String> input2 = Arrays.asList("D", "E", "F");

    Source.from(input1)
        .merge(Source.from(input2))
        .runForeach(
            new Procedure<String>() {
              public void apply(String elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    probe.expectMsgAllOf("A", "B", "C", "D", "E", "F");
  }

  @Test
  public void mustBeAbleToUseZipWith() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input1 = Arrays.asList("A", "B", "C");
    final Iterable<String> input2 = Arrays.asList("D", "E", "F");

    Source.from(input1)
        .zipWith(
            Source.from(input2),
            new Function2<String, String, String>() {
              public String apply(String s1, String s2) {
                return s1 + "-" + s2;
              }
            })
        .runForeach(
            new Procedure<String>() {
              public void apply(String elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    probe.expectMsgEquals("A-D");
    probe.expectMsgEquals("B-E");
    probe.expectMsgEquals("C-F");
  }

  @Test
  public void mustBeAbleToUseZip() throws Exception {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input1 = Arrays.asList("A", "B", "C");
    final Iterable<String> input2 = Arrays.asList("D", "E", "F");

    Source.from(input1)
        .zip(Source.from(input2))
        .runForeach(
            new Procedure<Pair<String, String>>() {
              public void apply(Pair<String, String> elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    probe.expectMsgEquals(new Pair<String, String>("A", "D"));
    probe.expectMsgEquals(new Pair<String, String>("B", "E"));
    probe.expectMsgEquals(new Pair<String, String>("C", "F"));
  }

  @Test
  public void mustBeAbleToUseMerge2() {
    final JavaTestKit probe = new JavaTestKit(system);
    final Iterable<String> input1 = Arrays.asList("A", "B", "C");
    final Iterable<String> input2 = Arrays.asList("D", "E", "F");

    Source.from(input1)
        .merge(Source.from(input2))
        .runForeach(
            new Procedure<String>() {
              public void apply(String elem) {
                probe.getRef().tell(elem, ActorRef.noSender());
              }
            },
            materializer);

    probe.expectMsgAllOf("A", "B", "C", "D", "E", "F");
  }

  @Test
  public void mustBeAbleToUseInitialTimeout() throws Throwable {
    try {
      try {
        Source.maybe()
            .initialTimeout(Duration.create(1, "second"))
            .runWith(Sink.head(), materializer)
            .toCompletableFuture()
            .get(3, TimeUnit.SECONDS);
        fail("A TimeoutException was expected");
      } catch (ExecutionException e) {
        throw e.getCause();
      }
    } catch (TimeoutException e) {
      // expected
    }
  }

  @Test
  public void mustBeAbleToUseCompletionTimeout() throws Throwable {
    try {
      try {
        Source.maybe()
            .completionTimeout(Duration.create(1, "second"))
            .runWith(Sink.head(), materializer)
            .toCompletableFuture()
            .get(3, TimeUnit.SECONDS);
        fail("A TimeoutException was expected");
      } catch (ExecutionException e) {
        throw e.getCause();
      }
    } catch (TimeoutException e) {
      // expected
    }
  }

  @Test
  public void mustBeAbleToUseIdleTimeout() throws Throwable {
    try {
      try {
        Source.maybe()
            .idleTimeout(Duration.create(1, "second"))
            .runWith(Sink.head(), materializer)
            .toCompletableFuture()
            .get(3, TimeUnit.SECONDS);
        fail("A TimeoutException was expected");
      } catch (ExecutionException e) {
        throw e.getCause();
      }
    } catch (TimeoutException e) {
      // expected
    }
  }

  @Test
  public void mustBeAbleToUseIdleInject() throws Exception {
    Integer result =
        Source.maybe()
            .keepAlive(
                Duration.create(1, "second"),
                new Creator<Integer>() {
                  public Integer create() {
                    return 0;
                  }
                })
            .takeWithin(Duration.create(1500, "milliseconds"))
            .runWith(Sink.<Integer>head(), materializer)
            .toCompletableFuture()
            .get(3, TimeUnit.SECONDS);

    assertEquals((Object) 0, result);
  }

  public void mustSuitablyOverrideAttributeHandlingMethods() {
    @SuppressWarnings("unused")
    final Source<Integer, NotUsed> f =
        Source.single(42)
            .withAttributes(Attributes.name(""))
            .addAttributes(Attributes.asyncBoundary())
            .named("");
  }

  @Test
  public void mustBeAbleToUseThrottle() throws Exception {
    Integer result =
        Source.from(Arrays.asList(0, 1, 2))
            .throttle(10, FiniteDuration.create(1, TimeUnit.SECONDS), 10, ThrottleMode.shaping())
            .throttle(10, FiniteDuration.create(1, TimeUnit.SECONDS), 10, ThrottleMode.enforcing())
            .runWith(Sink.head(), materializer)
            .toCompletableFuture()
            .get(3, TimeUnit.SECONDS);

    assertEquals((Object) 0, result);
  }
}
示例#8
0
public class UntypedActorDocTest {

  @ClassRule
  public static AkkaJUnitActorSystemResource actorSystemResource =
      new AkkaJUnitActorSystemResource("UntypedActorDocTest", AkkaSpec.testConf());

  private final ActorSystem system = actorSystemResource.getSystem();

  // #creating-props-config
  static class MyActorC implements Creator<MyActor> {
    @Override
    public MyActor create() {
      return new MyActor("...");
    }
  }

  // #creating-props-config

  @SuppressWarnings("unused")
  @Test
  public void createProps() {
    // #creating-props-config
    Props props1 = Props.create(MyUntypedActor.class);
    Props props2 = Props.create(MyActor.class, "...");
    Props props3 = Props.create(new MyActorC());
    // #creating-props-config
  }

  // #parametric-creator
  static class ParametricCreator<T extends MyActor> implements Creator<T> {
    @Override
    public T create() {
      // ... fabricate actor here
      // #parametric-creator
      return null;
      // #parametric-creator
    }
  }
  // #parametric-creator

  @Test
  public void systemActorOf() {
    // #system-actorOf
    // ActorSystem is a heavy object: create only one per application
    final ActorSystem system = ActorSystem.create("MySystem");
    final ActorRef myActor = system.actorOf(Props.create(MyUntypedActor.class), "myactor");
    // #system-actorOf
    try {
      new JavaTestKit(system) {
        {
          myActor.tell("hello", getRef());
          expectMsgEquals("hello");
        }
      };
    } finally {
      JavaTestKit.shutdownActorSystem(system);
    }
  }

  @Test
  public void contextActorOf() {
    new JavaTestKit(system) {
      {
        // #context-actorOf
        class A extends UntypedActor {
          final ActorRef child =
              getContext().actorOf(Props.create(MyUntypedActor.class), "myChild");
          // #plus-some-behavior
          @Override
          public void onReceive(Object msg) {
            getSender().tell(child, getSelf());
          }
          // #plus-some-behavior
        }
        // #context-actorOf
        final ActorRef top = system.actorOf(Props.create(A.class, this));
        top.tell("hello", getRef());
        final ActorRef child = expectMsgClass(ActorRef.class);
        child.tell("hello", getRef());
        expectMsgEquals("hello");
      }
    };
  }

  // this is just to make the test below a tiny fraction nicer
  private ActorSystem getContext() {
    return system;
  }

  static
  // #creating-indirectly
  class DependencyInjector implements IndirectActorProducer {
    final Object applicationContext;
    final String beanName;

    public DependencyInjector(Object applicationContext, String beanName) {
      this.applicationContext = applicationContext;
      this.beanName = beanName;
    }

    @Override
    public Class<? extends Actor> actorClass() {
      return MyActor.class;
    }

    @Override
    public MyActor produce() {
      MyActor result;
      // #obtain-fresh-Actor-instance-from-DI-framework
      result = new MyActor((String) applicationContext);
      // #obtain-fresh-Actor-instance-from-DI-framework
      return result;
    }
  }
  // #creating-indirectly

  @Test
  public void indirectActorOf() {
    final String applicationContext = "...";
    // #creating-indirectly

    final ActorRef myActor =
        getContext()
            .actorOf(
                Props.create(DependencyInjector.class, applicationContext, "MyActor"), "myactor3");
    // #creating-indirectly
    new JavaTestKit(system) {
      {
        myActor.tell("hello", getRef());
        expectMsgEquals("...");
      }
    };
  }

  @SuppressWarnings("unused")
  @Test
  public void usingAsk() throws Exception {
    ActorRef myActor = system.actorOf(Props.create(MyAskActor.class, this), "myactor5");

    // #using-ask
    Future<Object> future = Patterns.ask(myActor, "Hello", 1000);
    Object result = Await.result(future, Duration.create(1, TimeUnit.SECONDS));
    // #using-ask
  }

  @Test
  public void receiveTimeout() {
    final ActorRef myActor = system.actorOf(Props.create(MyReceiveTimeoutUntypedActor.class));
    new JavaTestKit(system) {
      {
        new Within(
            Duration.create(1, TimeUnit.SECONDS), Duration.create(1500, TimeUnit.MILLISECONDS)) {
          @Override
          protected void run() {
            myActor.tell("Hello", getRef());
            expectMsgEquals("Hello world");
            expectMsgEquals("timeout");
          }
        };
      }
    };
  }

  @Test
  public void usePoisonPill() {
    final ActorRef myActor = system.actorOf(Props.create(MyUntypedActor.class));
    new JavaTestKit(system) {
      {
        final ActorRef sender = getRef();
        // #poison-pill
        myActor.tell(akka.actor.PoisonPill.getInstance(), sender);
        // #poison-pill
        watch(myActor);
        expectTerminated(myActor);
      }
    };
  }

  @Test
  public void useKill() {
    new JavaTestKit(system) {
      {
        class Master extends UntypedActor {
          private SupervisorStrategy strategy =
              new OneForOneStrategy(
                  -1,
                  Duration.Undefined(),
                  new Function<Throwable, Directive>() {
                    @Override
                    public Directive apply(Throwable thr) {
                      if (thr instanceof ActorKilledException) {
                        target.tell("killed", getSelf());
                        getContext().stop(getSelf());
                        return SupervisorStrategy.stop();
                      }
                      return SupervisorStrategy.escalate();
                    }
                  });
          final ActorRef target;
          ActorRef child;

          // #preStart
          @Override
          public void preStart() {
            child = getContext().actorOf(Props.empty());
          }
          // #preStart

          @SuppressWarnings("unused")
          public Master(ActorRef target) {
            this.target = target;

            /*
             * Only compilation of `forward` is verified here.
             */
            final Object result = "";
            // #forward
            target.forward(result, getContext());
            // #forward
          }

          @Override
          public SupervisorStrategy supervisorStrategy() {
            return strategy;
          }

          // #reply
          @Override
          public void onReceive(Object msg) {
            Object result =
                // #calculate-result
                child;
            // #calculate-result

            // do not forget the second argument!
            getSender().tell(result, getSelf());
          }
          // #reply

          // #postStop
          @Override
          public void postStop() {
            // #clean-up-resources-here
            final String message = "stopped";
            // #tell
            // don’t forget to think about who is the sender (2nd argument)
            target.tell(message, getSelf());
            // #tell
            // #clean-up-resources-here
          }
          // #postStop
        }
        final ActorRef master = system.actorOf(Props.create(Master.class, this, getRef()));
        expectMsgEquals("");
        master.tell("", getRef());
        final ActorRef victim = expectMsgClass(ActorRef.class);
        // #kill
        victim.tell(akka.actor.Kill.getInstance(), ActorRef.noSender());
        // #kill
        expectMsgEquals("killed");
        expectMsgEquals("stopped");
        assert getLastSender().equals(master);
      }
    };
  }

  @Test
  public void useBecome() {
    new JavaTestKit(system) {
      {
        ActorRef myActor = system.actorOf(Props.create(HotSwapActor.class));
        myActor.tell("foo", getRef());
        myActor.tell("bar", getRef());
        expectMsgEquals("I am already happy :-)");
        myActor.tell("bar", getRef());
        expectMsgEquals("I am already happy :-)");
      }
    };
  }

  @Test
  public void useWatch() throws Exception {
    ActorRef myActor = system.actorOf(Props.create(WatchActor.class));
    Future<Object> future = Patterns.ask(myActor, "kill", 1000);
    assert Await.result(future, Duration.create("1 second")).equals("finished");
  }

  // compilation test only
  public void compileSelections() {
    // #selection-local
    // will look up this absolute path
    getContext().actorSelection("/user/serviceA/actor");
    // will look up sibling beneath same supervisor
    getContext().actorSelection("../joe");
    // #selection-local

    // #selection-wildcard
    // will look all children to serviceB with names starting with worker
    getContext().actorSelection("/user/serviceB/worker*");
    // will look up all siblings beneath same supervisor
    getContext().actorSelection("../*");
    // #selection-wildcard

    // #selection-remote
    getContext().actorSelection("akka.tcp://app@otherhost:1234/user/serviceB");
    // #selection-remote
  }

  @Test
  public void useIdentify() throws Exception {
    new JavaTestKit(system) {
      {
        ActorRef a = system.actorOf(Props.create(MyUntypedActor.class), "another");
        ActorRef b = system.actorOf(Props.create(Follower.class, getRef()));
        expectMsgEquals(a);
        system.stop(a);
        watch(b);
        expectTerminated(b);
      }
    };
  }

  @Test
  public void usePatternsGracefulStop() throws Exception {
    ActorRef actorRef = system.actorOf(Props.create(Manager.class));
    // #gracefulStop
    try {
      Future<Boolean> stopped =
          gracefulStop(actorRef, Duration.create(5, TimeUnit.SECONDS), Manager.SHUTDOWN);
      Await.result(stopped, Duration.create(6, TimeUnit.SECONDS));
      // the actor has been stopped
    } catch (AskTimeoutException e) {
      // the actor wasn't stopped within 5 seconds
    }
    // #gracefulStop
  }

  class Result {
    final String x;
    final String s;

    public Result(String x, String s) {
      this.x = x;
      this.s = s;
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((s == null) ? 0 : s.hashCode());
      result = prime * result + ((x == null) ? 0 : x.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) return true;
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      Result other = (Result) obj;
      if (s == null) {
        if (other.s != null) return false;
      } else if (!s.equals(other.s)) return false;
      if (x == null) {
        if (other.x != null) return false;
      } else if (!x.equals(other.x)) return false;
      return true;
    }
  }

  @Test
  public void usePatternsAskPipe() {
    new JavaTestKit(system) {
      {
        ActorRef actorA = system.actorOf(Props.create(MyUntypedActor.class));
        ActorRef actorB = system.actorOf(Props.create(MyUntypedActor.class));
        ActorRef actorC = getRef();

        // #ask-pipe
        final Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));

        final ArrayList<Future<Object>> futures = new ArrayList<Future<Object>>();
        futures.add(ask(actorA, "request", 1000)); // using 1000ms timeout
        futures.add(ask(actorB, "another request", t)); // using timeout from
        // above

        final Future<Iterable<Object>> aggregate = Futures.sequence(futures, system.dispatcher());

        final Future<Result> transformed =
            aggregate.map(
                new Mapper<Iterable<Object>, Result>() {
                  public Result apply(Iterable<Object> coll) {
                    final Iterator<Object> it = coll.iterator();
                    final String x = (String) it.next();
                    final String s = (String) it.next();
                    return new Result(x, s);
                  }
                },
                system.dispatcher());

        pipe(transformed, system.dispatcher()).to(actorC);
        // #ask-pipe

        expectMsgEquals(new Result("request", "another request"));
      }
    };
  }

  public
  // #props-factory
  static class DemoActor extends UntypedActor {

    /**
     * Create Props for an actor of this type.
     *
     * @param magicNumber The magic number to be passed to this actor’s constructor.
     * @return a Props for creating this actor, which can then be further configured (e.g. calling
     *     `.withDispatcher()` on it)
     */
    public static Props props(final int 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;

    public DemoActor(int magicNumber) {
      this.magicNumber = magicNumber;
    }

    @Override
    public void onReceive(Object msg) {
      // some behavior here
    }
  }

  // #props-factory
  @Test
  public void demoActor() {
    // #props-factory
    system.actorOf(DemoActor.props(42), "demo");
    // #props-factory
  }

  public static class MyActor extends UntypedActor {

    final String s;

    public MyActor(String s) {
      this.s = s;
    }

    public void onReceive(Object message) {
      getSender().tell(s, getSelf());
    }

    /*
     * This section must be kept in sync with the actual Actor trait.
     *
     * BOYSCOUT RULE: whenever you read this, verify that!
     */
    // #lifecycle-callbacks
    public void preStart() {}

    public void preRestart(Throwable reason, scala.Option<Object> message) {
      for (ActorRef each : getContext().getChildren()) {
        getContext().unwatch(each);
        getContext().stop(each);
      }
      postStop();
    }

    public void postRestart(Throwable reason) {
      preStart();
    }

    public void postStop() {}
    // #lifecycle-callbacks
  }

  public class MyAskActor extends UntypedActor {

    public void onReceive(Object message) throws Exception {
      // #reply-exception
      try {
        String result = operation();
        getSender().tell(result, getSelf());
      } catch (Exception e) {
        getSender().tell(new akka.actor.Status.Failure(e), getSelf());
        throw e;
      }
      // #reply-exception
    }

    private String operation() {
      return "Hi";
    }
  }

  public
  // #gracefulStop-actor
  static class Manager extends UntypedActor {

    public static final String SHUTDOWN = "shutdown";

    ActorRef worker =
        getContext().watch(getContext().actorOf(Props.create(Cruncher.class), "worker"));

    public void onReceive(Object message) {
      if (message.equals("job")) {
        worker.tell("crunch", getSelf());
      } else if (message.equals(SHUTDOWN)) {
        worker.tell(PoisonPill.getInstance(), getSelf());
        getContext().become(shuttingDown);
      }
    }

    Procedure<Object> shuttingDown =
        new Procedure<Object>() {
          @Override
          public void apply(Object message) {
            if (message.equals("job")) {
              getSender().tell("service unavailable, shutting down", getSelf());
            } else if (message instanceof Terminated) {
              getContext().stop(getSelf());
            }
          }
        };
  }
  // #gracefulStop-actor

  static class Cruncher extends UntypedActor {
    public void onReceive(Object message) {
      // crunch...
    }
  }

  public
  // #hot-swap-actor
  static class HotSwapActor extends UntypedActor {

    Procedure<Object> angry =
        new Procedure<Object>() {
          @Override
          public void apply(Object message) {
            if (message.equals("bar")) {
              getSender().tell("I am already angry?", getSelf());
            } else if (message.equals("foo")) {
              getContext().become(happy);
            }
          }
        };

    Procedure<Object> happy =
        new Procedure<Object>() {
          @Override
          public void apply(Object message) {
            if (message.equals("bar")) {
              getSender().tell("I am already happy :-)", getSelf());
            } else if (message.equals("foo")) {
              getContext().become(angry);
            }
          }
        };

    public void onReceive(Object message) {
      if (message.equals("bar")) {
        getContext().become(angry);
      } else if (message.equals("foo")) {
        getContext().become(happy);
      } else {
        unhandled(message);
      }
    }
  }

  // #hot-swap-actor

  public
  // #stash
  static class ActorWithProtocol extends UntypedActorWithStash {
    public void onReceive(Object msg) {
      if (msg.equals("open")) {
        unstashAll();
        getContext()
            .become(
                new Procedure<Object>() {
                  public void apply(Object msg) throws Exception {
                    if (msg.equals("write")) {
                      // do writing...
                    } else if (msg.equals("close")) {
                      unstashAll();
                      getContext().unbecome();
                    } else {
                      stash();
                    }
                  }
                },
                false); // add behavior on top instead of replacing
      } else {
        stash();
      }
    }
  }
  // #stash

  public
  // #watch
  static class WatchActor extends UntypedActor {
    final ActorRef child = this.getContext().actorOf(Props.empty(), "child");

    {
      this.getContext().watch(child); // <-- the only call needed for registration
    }

    ActorRef lastSender = getContext().system().deadLetters();

    @Override
    public void onReceive(Object message) {
      if (message.equals("kill")) {
        getContext().stop(child);
        lastSender = getSender();
      } else if (message instanceof Terminated) {
        final Terminated t = (Terminated) message;
        if (t.getActor() == child) {
          lastSender.tell("finished", getSelf());
        }
      } else {
        unhandled(message);
      }
    }
  }
  // #watch

  public
  // #identify
  static class Follower extends UntypedActor {
    final String identifyId = "1";

    {
      ActorSelection selection = getContext().actorSelection("/user/another");
      selection.tell(new Identify(identifyId), getSelf());
    }

    ActorRef another;

    // #test-omitted
    final ActorRef probe;

    public Follower(ActorRef probe) {
      this.probe = probe;
    }
    // #test-omitted

    @Override
    public void onReceive(Object message) {
      if (message instanceof ActorIdentity) {
        ActorIdentity identity = (ActorIdentity) message;
        if (identity.correlationId().equals(identifyId)) {
          ActorRef ref = identity.getRef();
          if (ref == null) getContext().stop(getSelf());
          else {
            another = ref;
            getContext().watch(another);
            // #test-omitted
            probe.tell(ref, getSelf());
            // #test-omitted
          }
        }
      } else if (message instanceof Terminated) {
        final Terminated t = (Terminated) message;
        if (t.getActor().equals(another)) {
          getContext().stop(getSelf());
        }
      } else {
        unhandled(message);
      }
    }
  }
  // #identify

}