Пример #1
0
 abstract static class Example1 {
   // #first-sample
   // #materializer-setup
   final ActorSystem system = ActorSystem.create("reactive-tweets");
   final Materializer mat = ActorMaterializer.create(system);
   // #first-sample
   // #materializer-setup
 }
Пример #2
0
  /**
   * Create a new WSClient.
   *
   * <p>This client holds on to resources such as connections and threads, and so must be closed
   * after use.
   *
   * <p>If the URL passed into the url method of this client is a host relative absolute path (that
   * is, if it starts with /), then this client will make the request on localhost using the
   * supplied port. This is particularly useful in test situations.
   *
   * @param port The port to use on localhost when relative URLs are requested.
   * @return A running WS client.
   * @deprecated as of 2.6, not to be used. This method is not appropriate outside of testing
   *     context, because it makes many assumptions about the url, starts up a new client and
   *     actorsystem on every call, and hardcodes the config to something other than the app config.
   */
  @Deprecated
  public static WSClient newClient(final int port) {
    AsyncHttpClientConfig config =
        new DefaultAsyncHttpClientConfig.Builder()
            .setMaxRequestRetry(0)
            .setShutdownQuietPeriod(0)
            .setShutdownTimeout(0)
            .build();

    String name = "ws-java-newClient";
    final ActorSystem system = ActorSystem.create(name);
    ActorMaterializerSettings settings = ActorMaterializerSettings.create(system);
    ActorMaterializer materializer = ActorMaterializer.create(settings, system, name);

    final WSClient client = new AhcWSClient(config, materializer);

    return new WSClient() {
      public Object getUnderlying() {
        return client.getUnderlying();
      }

      public WSRequest url(String url) {
        if (url.startsWith("/") && port != -1) {
          return client.url("http://localhost:" + port + url);
        } else {
          return client.url(url);
        }
      }

      public void close() throws IOException {
        try {
          client.close();
        } finally {
          system.terminate();
        }
      }
    };
  }
  public static void server(int port, ActorSystem system) {
    /* */
    final Materializer materializer = ActorMaterializer.create(system);

    Http
        /* */
        .get(system)
        /* */
        .bind("localhost", port, materializer)
        /* */
        .to(
            Sink
                /* */
                .foreach(
                connection ->
                    /* */
                    connection.handleWith(
                        /* */
                        Flow.of(HttpRequest.class)
                            /* */
                            .map(
                                request -> {
                                  /* */
                                  if (request.method() == HttpMethods.GET
                                      && request.getUri().path().equals("/")) {
                                    /* */
                                    return HttpResponse.create()
                                        .withEntity(
                                            MediaTypes.TEXT_HTML.toContentType(), "Hello world!");
                                  }
                                  /* */
                                  return HttpResponse.create().withStatus(404);
                                }),
                        materializer)))
        /* */
        .run(materializer);
  }
Пример #4
0
 @BeforeClass
 public static void setup() {
   system = ActorSystem.create("RecipeDecompress");
   mat = ActorMaterializer.create(system);
 }
  public static void client(int port, ActorSystem system) {
    final ActorMaterializer materializer = ActorMaterializer.create(system);

    // Todo display in logger
    Http.get(system).singleRequest(HttpRequest.create("localhost:" + port), materializer);
  }
Пример #6
0
public class RecipeSeq extends RecipeTest {
  static ActorSystem system;

  @BeforeClass
  public static void setup() {
    system = ActorSystem.create("RecipeLoggingElements");
  }

  @AfterClass
  public static void tearDown() {
    JavaTestKit.shutdownActorSystem(system);
    system = null;
  }

  final Materializer mat = ActorMaterializer.create(system);

  @Test
  public void drainSourceToList() throws Exception {
    new JavaTestKit(system) {
      {
        final Source<String, NotUsed> mySource = Source.from(Arrays.asList("1", "2", "3"));
        // #draining-to-list-unsafe
        // Dangerous: might produce a collection with 2 billion elements!
        final CompletionStage<List<String>> strings = mySource.runWith(Sink.seq(), mat);
        // #draining-to-list-unsafe

        strings.toCompletableFuture().get(3, TimeUnit.SECONDS);
      }
    };
  }

  @Test
  public void drainSourceToListWithLimit() throws Exception {
    new JavaTestKit(system) {
      {
        final Source<String, NotUsed> mySource = Source.from(Arrays.asList("1", "2", "3"));
        // #draining-to-list-safe
        final int MAX_ALLOWED_SIZE = 100;

        // OK. Future will fail with a `StreamLimitReachedException`
        // if the number of incoming elements is larger than max
        final CompletionStage<List<String>> strings =
            mySource.limit(MAX_ALLOWED_SIZE).runWith(Sink.seq(), mat);
        // #draining-to-list-safe

        strings.toCompletableFuture().get(1, TimeUnit.SECONDS);
      }
    };
  }

  public void drainSourceToListWithTake() throws Exception {
    new JavaTestKit(system) {
      {
        final Source<String, NotUsed> mySource = Source.from(Arrays.asList("1", "2", "3"));
        final int MAX_ALLOWED_SIZE = 100;

        // #draining-to-list-safe

        // OK. Collect up until max-th elements only, then cancel upstream
        final CompletionStage<List<String>> strings =
            mySource.take(MAX_ALLOWED_SIZE).runWith(Sink.seq(), mat);
        // #draining-to-list-safe

        strings.toCompletableFuture().get(1, TimeUnit.SECONDS);
      }
    };
  }
}
Пример #7
0
public class RecipeWorkerPool extends RecipeTest {
  static ActorSystem system;

  @BeforeClass
  public static void setup() {
    system = ActorSystem.create("RecipeWorkerPool");
  }

  @AfterClass
  public static void tearDown() {
    JavaTestKit.shutdownActorSystem(system);
    system = null;
  }

  final Materializer mat = ActorMaterializer.create(system);

  // #worker-pool
  public static <In, Out> Flow<In, Out, BoxedUnit> balancer(
      Flow<In, Out, BoxedUnit> worker, int workerCount) {
    return Flow.fromGraph(
        GraphDSL.create(
            b -> {
              boolean waitForAllDownstreams = true;
              final UniformFanOutShape<In, In> balance =
                  b.add(Balance.<In>create(workerCount, waitForAllDownstreams));
              final UniformFanInShape<Out, Out> merge = b.add(Merge.<Out>create(workerCount));

              for (int i = 0; i < workerCount; i++) {
                b.from(balance.out(i)).via(b.add(worker)).toInlet(merge.in(i));
              }

              return FlowShape.of(balance.in(), merge.out());
            }));
  }
  // #worker-pool

  @Test
  public void workForVersion1() throws Exception {
    new JavaTestKit(system) {
      {
        Source<Message, BoxedUnit> data =
            Source.from(Arrays.asList("1", "2", "3", "4", "5")).map(t -> new Message(t));

        Flow<Message, Message, BoxedUnit> worker =
            Flow.of(Message.class).map(m -> new Message(m.msg + " done"));

        // #worker-pool2
        Flow<Message, Message, BoxedUnit> balancer = balancer(worker, 3);
        Source<Message, BoxedUnit> processedJobs = data.via(balancer);
        // #worker-pool2

        FiniteDuration timeout = FiniteDuration.create(200, TimeUnit.MILLISECONDS);
        Future<List<String>> future =
            processedJobs.map(m -> m.msg).grouped(10).runWith(Sink.head(), mat);
        List<String> got = Await.result(future, timeout);
        assertTrue(got.contains("1 done"));
        assertTrue(got.contains("2 done"));
        assertTrue(got.contains("3 done"));
        assertTrue(got.contains("4 done"));
        assertTrue(got.contains("5 done"));
      }
    };
  }
}
Пример #8
0
public class GraphStageDocTest {
  static ActorSystem system;

  @BeforeClass
  public static void setup() {
    system = ActorSystem.create("FlowGraphDocTest");
  }

  @AfterClass
  public static void tearDown() {
    JavaTestKit.shutdownActorSystem(system);
    system = null;
  }

  final Materializer mat = ActorMaterializer.create(system);

  // #simple-source
  public class NumbersSource extends GraphStage<SourceShape<Integer>> {
    // Define the (sole) output port of this stage
    public final Outlet<Integer> out = Outlet.create("NumbersSource.out");

    // Define the shape of this stage, which is SourceShape with the port we defined above
    private final SourceShape<Integer> shape = SourceShape.of(out);

    @Override
    public SourceShape<Integer> shape() {
      return shape;
    }

    // This is where the actual (possibly stateful) logic is created
    @Override
    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new GraphStageLogic(shape()) {
        // All state MUST be inside the GraphStageLogic,
        // never inside the enclosing GraphStage.
        // This state is safe to access and modify from all the
        // callbacks that are provided by GraphStageLogic and the
        // registered handlers.
        private int counter = 1;

        {
          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  push(out, counter);
                  counter += 1;
                }
              });
        }
      };
    }
  }
  // #simple-source

  @Test
  public void demonstrateCustomSourceUsage() throws Exception {
    // #simple-source-usage
    // A GraphStage is a proper Graph, just like what GraphDSL.create would return
    Graph<SourceShape<Integer>, NotUsed> sourceGraph = new NumbersSource();

    // Create a Source from the Graph to access the DSL
    Source<Integer, NotUsed> mySource = Source.fromGraph(sourceGraph);

    // Returns 55
    CompletionStage<Integer> result1 = mySource.take(10).runFold(0, (sum, next) -> sum + next, mat);

    // The source is reusable. This returns 5050
    CompletionStage<Integer> result2 =
        mySource.take(100).runFold(0, (sum, next) -> sum + next, mat);
    // #simple-source-usage

    assertEquals(result1.toCompletableFuture().get(3, TimeUnit.SECONDS), (Integer) 55);
    assertEquals(result2.toCompletableFuture().get(3, TimeUnit.SECONDS), (Integer) 5050);
  }

  // #one-to-one
  public class Map<A, B> extends GraphStage<FlowShape<A, B>> {

    private final Function<A, B> f;

    public Map(Function<A, B> f) {
      this.f = f;
    }

    public final Inlet<A> in = Inlet.create("Map.in");
    public final Outlet<B> out = Outlet.create("Map.out");

    private final FlowShape<A, B> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, B> shape() {
      return shape;
    }

    @Override
    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new GraphStageLogic(shape) {

        {
          setHandler(
              in,
              new AbstractInHandler() {
                @Override
                public void onPush() {
                  try {
                    push(out, f.apply(grab(in)));
                  } catch (Exception ex) {
                    failStage(ex);
                  }
                }
              });
          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  pull(in);
                }
              });
        }
      };
    }
  }
  // #one-to-one

  @Test
  public void demonstrateOneToOne() throws Exception {
    // tests:
    final Graph<FlowShape<String, Integer>, NotUsed> stringLength =
        Flow.fromGraph(
            new Map<String, Integer>(
                new Function<String, Integer>() {
                  @Override
                  public Integer apply(String str) {
                    return str.length();
                  }
                }));

    CompletionStage<Integer> result =
        Source.from(Arrays.asList("one", "two", "three"))
            .via(stringLength)
            .runFold(0, (sum, n) -> sum + n, mat);

    assertEquals(new Integer(11), result.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  // #many-to-one
  public final class Filter<A> extends GraphStage<FlowShape<A, A>> {

    private final Predicate<A> p;

    public Filter(Predicate<A> p) {
      this.p = p;
    }

    public final Inlet<A> in = Inlet.create("Filter.in");
    public final Outlet<A> out = Outlet.create("Filter.out");

    private final FlowShape<A, A> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, A> shape() {
      return shape;
    }

    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new GraphStageLogic(shape) {
        {
          setHandler(
              in,
              new AbstractInHandler() {
                @Override
                public void onPush() {
                  A elem = grab(in);
                  if (p.test(elem)) {
                    push(out, elem);
                  } else {
                    pull(in);
                  }
                }
              });

          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  pull(in);
                }
              });
        }
      };
    }
  }
  // #many-to-one

  @Test
  public void demonstrateAManyToOneElementGraphStage() throws Exception {

    // tests:
    Graph<FlowShape<Integer, Integer>, NotUsed> evenFilter =
        Flow.fromGraph(new Filter<Integer>(n -> n % 2 == 0));

    CompletionStage<Integer> result =
        Source.from(Arrays.asList(1, 2, 3, 4, 5, 6))
            .via(evenFilter)
            .runFold(0, (elem, sum) -> sum + elem, mat);

    assertEquals(new Integer(12), result.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  // #one-to-many
  public class Duplicator<A> extends GraphStage<FlowShape<A, A>> {

    public final Inlet<A> in = Inlet.create("Duplicator.in");
    public final Outlet<A> out = Outlet.create("Duplicator.out");

    private final FlowShape<A, A> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, A> shape() {
      return shape;
    }

    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new GraphStageLogic(shape) {
        // Again: note that all mutable state
        // MUST be inside the GraphStageLogic
        Option<A> lastElem = Option.none();

        {
          setHandler(
              in,
              new AbstractInHandler() {
                @Override
                public void onPush() {
                  A elem = grab(in);
                  lastElem = Option.some(elem);
                  push(out, elem);
                }

                @Override
                public void onUpstreamFinish() {
                  if (lastElem.isDefined()) {
                    emit(out, lastElem.get());
                  }
                  complete(out);
                }
              });

          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  if (lastElem.isDefined()) {
                    push(out, lastElem.get());
                    lastElem = Option.none();
                  } else {
                    pull(in);
                  }
                }
              });
        }
      };
    }
  }
  // #one-to-many

  @Test
  public void demonstrateAOneToManyElementGraphStage() throws Exception {
    // tests:
    Graph<FlowShape<Integer, Integer>, NotUsed> duplicator =
        Flow.fromGraph(new Duplicator<Integer>());

    CompletionStage<Integer> result =
        Source.from(Arrays.asList(1, 2, 3)).via(duplicator).runFold(0, (n, sum) -> n + sum, mat);

    assertEquals(new Integer(12), result.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  // #simpler-one-to-many
  public class Duplicator2<A> extends GraphStage<FlowShape<A, A>> {

    public final Inlet<A> in = Inlet.create("Duplicator.in");
    public final Outlet<A> out = Outlet.create("Duplicator.out");

    private final FlowShape<A, A> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, A> shape() {
      return shape;
    }

    @Override
    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new GraphStageLogic(shape) {

        {
          setHandler(
              in,
              new AbstractInHandler() {
                @Override
                public void onPush() {
                  A elem = grab(in);
                  // this will temporarily suspend this handler until the two elems
                  // are emitted and then reinstates it
                  emitMultiple(out, Arrays.asList(elem, elem).iterator());
                }
              });

          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  pull(in);
                }
              });
        }
      };
    }
  }
  // #simpler-one-to-many

  @Test
  public void demonstrateASimplerOneToManyStage() throws Exception {
    // tests:
    Graph<FlowShape<Integer, Integer>, NotUsed> duplicator =
        Flow.fromGraph(new Duplicator2<Integer>());

    CompletionStage<Integer> result =
        Source.from(Arrays.asList(1, 2, 3)).via(duplicator).runFold(0, (n, sum) -> n + sum, mat);

    assertEquals(new Integer(12), result.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  @Test
  public void demonstrateChainingOfGraphStages() throws Exception {
    Graph<SinkShape<Integer>, CompletionStage<String>> sink =
        Sink.fold("", (acc, n) -> acc + n.toString());

    // #graph-stage-chain
    CompletionStage<String> resultFuture =
        Source.from(Arrays.asList(1, 2, 3, 4, 5))
            .via(new Filter<Integer>((n) -> n % 2 == 0))
            .via(new Duplicator<Integer>())
            .via(new Map<Integer, Integer>((n) -> n / 2))
            .runWith(sink, mat);

    // #graph-stage-chain

    assertEquals("1122", resultFuture.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  // #async-side-channel
  // will close upstream when the future completes
  public class KillSwitch<A> extends GraphStage<FlowShape<A, A>> {

    private final CompletionStage<Done> switchF;

    public KillSwitch(CompletionStage<Done> switchF) {
      this.switchF = switchF;
    }

    public final Inlet<A> in = Inlet.create("KillSwitch.in");
    public final Outlet<A> out = Outlet.create("KillSwitch.out");

    private final FlowShape<A, A> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, A> shape() {
      return shape;
    }

    @Override
    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new GraphStageLogic(shape) {

        {
          setHandler(
              in,
              new AbstractInHandler() {
                @Override
                public void onPush() {
                  push(out, grab(in));
                }
              });
          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  pull(in);
                }
              });
        }

        @Override
        public void preStart() {
          AsyncCallback<Done> callback =
              createAsyncCallback(
                  new Procedure<Done>() {
                    @Override
                    public void apply(Done param) throws Exception {
                      completeStage();
                    }
                  });

          ExecutionContext ec = system.dispatcher();
          switchF.thenAccept(callback::invoke);
        }
      };
    }
  }
  // #async-side-channel

  @Test
  public void demonstrateAnAsynchronousSideChannel() throws Exception {

    // tests:
    CompletableFuture<Done> switchF = new CompletableFuture<>();
    Graph<FlowShape<Integer, Integer>, NotUsed> killSwitch =
        Flow.fromGraph(new KillSwitch<>(switchF));

    ExecutionContext ec = system.dispatcher();

    CompletionStage<Integer> valueAfterKill = switchF.thenApply(in -> 4);

    CompletionStage<Integer> result =
        Source.from(Arrays.asList(1, 2, 3))
            .concat(Source.fromCompletionStage(valueAfterKill))
            .via(killSwitch)
            .runFold(0, (n, sum) -> n + sum, mat);

    switchF.complete(Done.getInstance());

    assertEquals(new Integer(6), result.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  // #timed
  // each time an event is pushed through it will trigger a period of silence
  public class TimedGate<A> extends GraphStage<FlowShape<A, A>> {

    private final FiniteDuration silencePeriod;

    public TimedGate(FiniteDuration silencePeriod) {
      this.silencePeriod = silencePeriod;
    }

    public final Inlet<A> in = Inlet.create("TimedGate.in");
    public final Outlet<A> out = Outlet.create("TimedGate.out");

    private final FlowShape<A, A> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, A> shape() {
      return shape;
    }

    @Override
    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new TimerGraphStageLogic(shape) {

        private boolean open = false;

        {
          setHandler(
              in,
              new AbstractInHandler() {
                @Override
                public void onPush() {
                  A elem = grab(in);
                  if (open) pull(in);
                  else {
                    push(out, elem);
                    open = true;
                    scheduleOnce("key", silencePeriod);
                  }
                }
              });
          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  pull(in);
                }
              });
        }

        @Override
        public void onTimer(Object key) {
          if (key.equals("key")) {
            open = false;
          }
        }
      };
    }
  }
  // #timed

  public void demonstrateAGraphStageWithATimer() throws Exception {
    // tests:
    CompletionStage<Integer> result =
        Source.from(Arrays.asList(1, 2, 3))
            .via(new TimedGate<>(Duration.create(2, "seconds")))
            .takeWithin(Duration.create(250, "millis"))
            .runFold(0, (n, sum) -> n + sum, mat);

    assertEquals(new Integer(1), result.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  // #materialized
  public class FirstValue<A>
      extends GraphStageWithMaterializedValue<FlowShape<A, A>, CompletionStage<A>> {

    public final Inlet<A> in = Inlet.create("FirstValue.in");
    public final Outlet<A> out = Outlet.create("FirstValue.out");

    private final FlowShape<A, A> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, A> shape() {
      return shape;
    }

    @Override
    public Tuple2<GraphStageLogic, CompletionStage<A>> createLogicAndMaterializedValue(
        Attributes inheritedAttributes) {
      Promise<A> promise = Futures.promise();

      GraphStageLogic logic =
          new GraphStageLogic(shape) {
            {
              setHandler(
                  in,
                  new AbstractInHandler() {
                    @Override
                    public void onPush() {
                      A elem = grab(in);
                      promise.success(elem);
                      push(out, elem);

                      // replace handler with one just forwarding
                      setHandler(
                          in,
                          new AbstractInHandler() {
                            @Override
                            public void onPush() {
                              push(out, grab(in));
                            }
                          });
                    }
                  });

              setHandler(
                  out,
                  new AbstractOutHandler() {
                    @Override
                    public void onPull() {
                      pull(in);
                    }
                  });
            }
          };

      return new Tuple2(logic, promise.future());
    }
  }
  // #materialized

  public void demonstrateACustomMaterializedValue() throws Exception {
    // tests:
    RunnableGraph<CompletionStage<Integer>> flow =
        Source.from(Arrays.asList(1, 2, 3))
            .viaMat(new FirstValue(), Keep.right())
            .to(Sink.ignore());

    CompletionStage<Integer> result = flow.run(mat);

    assertEquals(new Integer(1), result.toCompletableFuture().get(3, TimeUnit.SECONDS));
  }

  // #detached
  public class TwoBuffer<A> extends GraphStage<FlowShape<A, A>> {

    public final Inlet<A> in = Inlet.create("TwoBuffer.in");
    public final Outlet<A> out = Outlet.create("TwoBuffer.out");

    private final FlowShape<A, A> shape = FlowShape.of(in, out);

    @Override
    public FlowShape<A, A> shape() {
      return shape;
    }

    @Override
    public GraphStageLogic createLogic(Attributes inheritedAttributes) {
      return new GraphStageLogic(shape) {

        private final int SIZE = 2;
        private Queue<A> buffer = new ArrayDeque<>(SIZE);
        private boolean downstreamWaiting = false;

        private boolean isBufferFull() {
          return buffer.size() == SIZE;
        }

        @Override
        public void preStart() {
          // a detached stage needs to start upstream demand
          // itself as it is not triggered by downstream demand
          pull(in);
        }

        {
          setHandler(
              in,
              new AbstractInHandler() {
                @Override
                public void onPush() {
                  A elem = grab(in);
                  buffer.add(elem);
                  if (downstreamWaiting) {
                    downstreamWaiting = false;
                    A bufferedElem = buffer.poll();
                    push(out, bufferedElem);
                  }
                  if (!isBufferFull()) {
                    pull(in);
                  }
                }

                @Override
                public void onUpstreamFinish() {
                  if (!buffer.isEmpty()) {
                    // emit the rest if possible
                    emitMultiple(out, buffer.iterator());
                  }
                  completeStage();
                }
              });

          setHandler(
              out,
              new AbstractOutHandler() {
                @Override
                public void onPull() {
                  if (buffer.isEmpty()) {
                    downstreamWaiting = true;
                  } else {
                    A elem = buffer.poll();
                    push(out, elem);
                  }
                  if (!isBufferFull() && !hasBeenPulled(in)) {
                    pull(in);
                  }
                }
              });
        }
      };
    }
  }
  // #detached

  public void demonstrateADetachedGraphStage() throws Exception {
    // tests:
    CompletionStage<Integer> result1 =
        Source.from(Arrays.asList(1, 2, 3))
            .via(new TwoBuffer<>())
            .runFold(0, (acc, n) -> acc + n, mat);

    assertEquals(new Integer(6), result1.toCompletableFuture().get(3, TimeUnit.SECONDS));

    TestSubscriber.ManualProbe<Integer> subscriber = TestSubscriber.manualProbe(system);
    TestPublisher.Probe<Integer> publisher = TestPublisher.probe(0, system);
    RunnableGraph<NotUsed> flow2 =
        Source.fromPublisher(publisher).via(new TwoBuffer<>()).to(Sink.fromSubscriber(subscriber));

    flow2.run(mat);

    Subscription sub = subscriber.expectSubscription();
    // this happens even though the subscriber has not signalled any demand
    publisher.sendNext(1);
    publisher.sendNext(2);

    sub.cancel();
  }
}
Пример #9
0
@SuppressWarnings("unused")
public class TwitterStreamQuickstartDocTest {

  static ActorSystem system;

  @BeforeClass
  public static void setup() {
    system = ActorSystem.create("SampleActorTest");
  }

  @AfterClass
  public static void tearDown() {
    JavaTestKit.shutdownActorSystem(system);
    system = null;
  }

  abstract static class Model {
    // #model
    public static class Author {
      public final String handle;

      public Author(String handle) {
        this.handle = handle;
      }

      // ...

      // #model

      @Override
      public String toString() {
        return "Author(" + handle + ")";
      }

      @Override
      public boolean equals(Object o) {
        if (this == o) {
          return true;
        }
        if (o == null || getClass() != o.getClass()) {
          return false;
        }

        Author author = (Author) o;

        if (handle != null ? !handle.equals(author.handle) : author.handle != null) {
          return false;
        }

        return true;
      }

      @Override
      public int hashCode() {
        return handle != null ? handle.hashCode() : 0;
      }
      // #model
    }
    // #model

    // #model

    public static class Hashtag {
      public final String name;

      public Hashtag(String name) {
        this.name = name;
      }

      // ...
      // #model

      @Override
      public int hashCode() {
        return name.hashCode();
      }

      @Override
      public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        Hashtag other = (Hashtag) obj;
        return name.equals(other.name);
      }

      @Override
      public String toString() {
        return "Hashtag(" + name + ")";
      }
      // #model
    }
    // #model

    // #model

    public static class Tweet {
      public final Author author;
      public final long timestamp;
      public final String body;

      public Tweet(Author author, long timestamp, String body) {
        this.author = author;
        this.timestamp = timestamp;
        this.body = body;
      }

      public Set<Hashtag> hashtags() {
        return Arrays.asList(body.split(" "))
            .stream()
            .filter(a -> a.startsWith("#"))
            .map(a -> new Hashtag(a))
            .collect(Collectors.toSet());
      }

      // ...
      // #model

      @Override
      public String toString() {
        return "Tweet(" + author + "," + timestamp + "," + body + ")";
      }

      // #model
    }
    // #model

    // #model

    public static final Hashtag AKKA = new Hashtag("#akka");
    // #model

    public static final Source<Tweet, NotUsed> tweets =
        Source.from(
            Arrays.asList(
                new Tweet[] {
                  new Tweet(new Author("rolandkuhn"), System.currentTimeMillis(), "#akka rocks!"),
                  new Tweet(new Author("patriknw"), System.currentTimeMillis(), "#akka !"),
                  new Tweet(new Author("bantonsson"), System.currentTimeMillis(), "#akka !"),
                  new Tweet(new Author("drewhk"), System.currentTimeMillis(), "#akka !"),
                  new Tweet(
                      new Author("ktosopl"), System.currentTimeMillis(), "#akka on the rocks!"),
                  new Tweet(new Author("mmartynas"), System.currentTimeMillis(), "wow #akka !"),
                  new Tweet(new Author("akkateam"), System.currentTimeMillis(), "#akka rocks!"),
                  new Tweet(new Author("bananaman"), System.currentTimeMillis(), "#bananas rock!"),
                  new Tweet(new Author("appleman"), System.currentTimeMillis(), "#apples rock!"),
                  new Tweet(
                      new Author("drama"),
                      System.currentTimeMillis(),
                      "we compared #apples to #oranges!")
                }));
  }

  abstract static class Example0 {
    // #tweet-source
    Source<Tweet, NotUsed> tweets;
    // #tweet-source
  }

  abstract static class Example1 {
    // #first-sample
    // #materializer-setup
    final ActorSystem system = ActorSystem.create("reactive-tweets");
    final Materializer mat = ActorMaterializer.create(system);
    // #first-sample
    // #materializer-setup
  }

  static class Example2 {
    public void run(final Materializer mat)
        throws TimeoutException, InterruptedException, ExecutionException {
      // #backpressure-by-readline
      final CompletionStage<Done> completion =
          Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
              .map(
                  i -> {
                    System.out.println("map => " + i);
                    return i;
                  })
              .runForeach(
                  i ->
                      System.console()
                          .readLine("Element = %s continue reading? [press enter]\n", i),
                  mat);

      completion.toCompletableFuture().get(1, TimeUnit.SECONDS);
      // #backpressure-by-readline
    }
  }

  final Materializer mat = ActorMaterializer.create(system);

  @Test
  public void demonstrateFilterAndMap() {
    final SilenceSystemOut.System System = SilenceSystemOut.get();

    // #first-sample

    // #authors-filter-map
    final Source<Author, NotUsed> authors =
        tweets.filter(t -> t.hashtags().contains(AKKA)).map(t -> t.author);
    // #first-sample
    // #authors-filter-map

    new Object() {
      // #authors-collect
      JavaPartialFunction<Tweet, Author> collectFunction =
          new JavaPartialFunction<Tweet, Author>() {
            public Author apply(Tweet t, boolean isCheck) {
              if (t.hashtags().contains(AKKA)) {
                if (isCheck) return null; // to spare the expensive or side-effecting code
                return t.author;
              } else {
                throw noMatch();
              }
            }
          };

      final Source<Author, NotUsed> authors = tweets.collect(collectFunction);
      // #authors-collect
    };

    // #first-sample

    // #authors-foreachsink-println
    authors.runWith(Sink.foreach(a -> System.out.println(a)), mat);
    // #first-sample
    // #authors-foreachsink-println

    // #authors-foreach-println
    authors.runForeach(a -> System.out.println(a), mat);
    // #authors-foreach-println
  }

  @Test
  public void demonstrateMapConcat() {
    // #hashtags-mapConcat
    final Source<Hashtag, NotUsed> hashtags =
        tweets.mapConcat(t -> new ArrayList<Hashtag>(t.hashtags()));
    // #hashtags-mapConcat
  }

  abstract static class HiddenDefinitions {
    // #flow-graph-broadcast
    Sink<Author, NotUsed> writeAuthors;
    Sink<Hashtag, NotUsed> writeHashtags;
    // #flow-graph-broadcast
  }

  @Test
  public void demonstrateBroadcast() {
    final Sink<Author, CompletionStage<Done>> writeAuthors = Sink.ignore();
    final Sink<Hashtag, CompletionStage<Done>> writeHashtags = Sink.ignore();

    // #flow-graph-broadcast
    RunnableGraph.fromGraph(
            GraphDSL.create(
                b -> {
                  final UniformFanOutShape<Tweet, Tweet> bcast = b.add(Broadcast.create(2));
                  final FlowShape<Tweet, Author> toAuthor =
                      b.add(Flow.of(Tweet.class).map(t -> t.author));
                  final FlowShape<Tweet, Hashtag> toTags =
                      b.add(
                          Flow.of(Tweet.class)
                              .mapConcat(t -> new ArrayList<Hashtag>(t.hashtags())));
                  final SinkShape<Author> authors = b.add(writeAuthors);
                  final SinkShape<Hashtag> hashtags = b.add(writeHashtags);

                  b.from(b.add(tweets)).viaFanOut(bcast).via(toAuthor).to(authors);
                  b.from(bcast).via(toTags).to(hashtags);
                  return ClosedShape.getInstance();
                }))
        .run(mat);
    // #flow-graph-broadcast
  }

  long slowComputation(Tweet t) {
    try {
      // act as if performing some heavy computation
      Thread.sleep(500);
    } catch (InterruptedException e) {
    }
    return 42;
  }

  @Test
  public void demonstrateSlowProcessing() {
    // #tweets-slow-consumption-dropHead
    tweets
        .buffer(10, OverflowStrategy.dropHead())
        .map(t -> slowComputation(t))
        .runWith(Sink.ignore(), mat);
    // #tweets-slow-consumption-dropHead
  }

  @Test
  public void demonstrateCountOnFiniteStream() {
    // #tweets-fold-count
    final Sink<Integer, CompletionStage<Integer>> sumSink =
        Sink.<Integer, Integer>fold(0, (acc, elem) -> acc + elem);

    final RunnableGraph<CompletionStage<Integer>> counter =
        tweets.map(t -> 1).toMat(sumSink, Keep.right());

    final CompletionStage<Integer> sum = counter.run(mat);

    sum.thenAcceptAsync(
        c -> System.out.println("Total tweets processed: " + c), system.dispatcher());
    // #tweets-fold-count

    new Object() {
      // #tweets-fold-count-oneline
      final CompletionStage<Integer> sum = tweets.map(t -> 1).runWith(sumSink, mat);
      // #tweets-fold-count-oneline
    };
  }

  @Test
  public void demonstrateMaterializeMultipleTimes() {
    final Source<Tweet, NotUsed> tweetsInMinuteFromNow =
        tweets; // not really in second, just acting as if

    // #tweets-runnable-flow-materialized-twice
    final Sink<Integer, CompletionStage<Integer>> sumSink =
        Sink.<Integer, Integer>fold(0, (acc, elem) -> acc + elem);
    final RunnableGraph<CompletionStage<Integer>> counterRunnableGraph =
        tweetsInMinuteFromNow
            .filter(t -> t.hashtags().contains(AKKA))
            .map(t -> 1)
            .toMat(sumSink, Keep.right());

    // materialize the stream once in the morning
    final CompletionStage<Integer> morningTweetsCount = counterRunnableGraph.run(mat);
    // and once in the evening, reusing the blueprint
    final CompletionStage<Integer> eveningTweetsCount = counterRunnableGraph.run(mat);
    // #tweets-runnable-flow-materialized-twice

  }
}
Пример #10
0
 @BeforeClass
 public static void setup() {
   system = ActorSystem.create("CompositionDocTest");
   mat = ActorMaterializer.create(system);
 }