Example #1
0
  @Test
  public void reusingComponents() throws Exception {
    final Source<Integer, NotUsed> nestedSource =
        Source.single(0) // An atomic source
            .map(i -> i + 1) // an atomic processing stage
            .named("nestedSource"); // wraps up the current Source and gives it a name

    final Flow<Integer, Integer, NotUsed> nestedFlow =
        Flow.of(Integer.class)
            .filter(i -> i != 0) // an atomic processing stage
            .map(i -> i - 2) // another atomic processing stage
            .named("nestedFlow"); // wraps up the Flow, and gives it a name

    final Sink<Integer, NotUsed> nestedSink =
        nestedFlow
            .to(Sink.fold(0, (acc, i) -> acc + i)) // wire an atomic sink to the nestedFlow
            .named("nestedSink"); // wrap it up

    // #reuse
    // Create a RunnableGraph from our components
    final RunnableGraph<NotUsed> runnableGraph = nestedSource.to(nestedSink);

    // Usage is uniform, no matter if modules are composite or atomic
    final RunnableGraph<NotUsed> runnableGraph2 =
        Source.single(0).to(Sink.fold(0, (acc, i) -> acc + i));
    // #reuse
  }
  @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
  }
Example #3
0
 @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);
 }
Example #4
0
  @Test
  public void partialGraph() throws Exception {
    // #partial-graph
    final Graph<FlowShape<Integer, Integer>, NotUsed> partial =
        GraphDSL.create(
            builder -> {
              final UniformFanOutShape<Integer, Integer> B = builder.add(Broadcast.create(2));
              final UniformFanInShape<Integer, Integer> C = builder.add(Merge.create(2));
              final UniformFanOutShape<Integer, Integer> E = builder.add(Balance.create(2));
              final UniformFanInShape<Integer, Integer> F = builder.add(Merge.create(2));

              builder.from(F.out()).toInlet(C.in(0));
              builder.from(B).viaFanIn(C).toFanIn(F);
              builder
                  .from(B)
                  .via(builder.add(Flow.of(Integer.class).map(i -> i + 1)))
                  .viaFanOut(E)
                  .toFanIn(F);

              return new FlowShape<Integer, Integer>(B.in(), E.out(1));
            });

    // #partial-graph

    // #partial-use
    Source.single(0).via(partial).to(Sink.ignore());
    // #partial-use

    // #partial-flow-dsl
    // Convert the partial graph of FlowShape to a Flow to get
    // access to the fluid DSL (for example to be able to call .filter())
    final Flow<Integer, Integer, NotUsed> flow = Flow.fromGraph(partial);

    // Simple way to create a graph backed Source
    final Source<Integer, NotUsed> source =
        Source.fromGraph(
            GraphDSL.create(
                builder -> {
                  final UniformFanInShape<Integer, Integer> merge = builder.add(Merge.create(2));
                  builder.from(builder.add(Source.single(0))).toFanIn(merge);
                  builder.from(builder.add(Source.from(Arrays.asList(2, 3, 4)))).toFanIn(merge);
                  // Exposing exactly one output port
                  return new SourceShape<Integer>(merge.out());
                }));

    // Building a Sink with a nested Flow, using the fluid DSL
    final Sink<Integer, NotUsed> sink =
        Flow.of(Integer.class).map(i -> i * 2).drop(10).named("nestedFlow").to(Sink.head());

    // Putting all together
    final RunnableGraph<NotUsed> closed = source.via(flow.filter(i -> i > 1)).to(sink);
    // #partial-flow-dsl
  }
Example #5
0
 @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));
 }
Example #6
0
  @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);
  }
Example #7
0
  @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);
  }
Example #8
0
  @Test
  public void complexGraph() throws Exception {
    // #complex-graph
    RunnableGraph.fromGraph(
        GraphDSL.create(
            builder -> {
              final Outlet<Integer> A = builder.add(Source.single(0)).out();
              final UniformFanOutShape<Integer, Integer> B = builder.add(Broadcast.create(2));
              final UniformFanInShape<Integer, Integer> C = builder.add(Merge.create(2));
              final FlowShape<Integer, Integer> D =
                  builder.add(Flow.of(Integer.class).map(i -> i + 1));
              final UniformFanOutShape<Integer, Integer> E = builder.add(Balance.create(2));
              final UniformFanInShape<Integer, Integer> F = builder.add(Merge.create(2));
              final Inlet<Integer> G = builder.add(Sink.<Integer>foreach(System.out::println)).in();

              builder.from(F).toFanIn(C);
              builder.from(A).viaFanOut(B).viaFanIn(C).toFanIn(F);
              builder.from(B).via(D).viaFanOut(E).toFanIn(F);
              builder.from(E).toInlet(G);
              return ClosedShape.getInstance();
            }));
    // #complex-graph

    // #complex-graph-alt
    RunnableGraph.fromGraph(
        GraphDSL.create(
            builder -> {
              final SourceShape<Integer> A = builder.add(Source.single(0));
              final UniformFanOutShape<Integer, Integer> B = builder.add(Broadcast.create(2));
              final UniformFanInShape<Integer, Integer> C = builder.add(Merge.create(2));
              final FlowShape<Integer, Integer> D =
                  builder.add(Flow.of(Integer.class).map(i -> i + 1));
              final UniformFanOutShape<Integer, Integer> E = builder.add(Balance.create(2));
              final UniformFanInShape<Integer, Integer> F = builder.add(Merge.create(2));
              final SinkShape<Integer> G = builder.add(Sink.foreach(System.out::println));

              builder.from(F.out()).toInlet(C.in(0));
              builder.from(A).toInlet(B.in());
              builder.from(B.out(0)).toInlet(C.in(1));
              builder.from(C.out()).toInlet(F.in(0));
              builder.from(B.out(1)).via(D).toInlet(E.in());
              builder.from(E.out(0)).toInlet(F.in(1));
              builder.from(E.out(1)).to(G);
              return ClosedShape.getInstance();
            }));
    // #complex-graph-alt
  }
Example #9
0
 @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);
 }
Example #10
0
  @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);
  }
Example #11
0
 @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);
 }
Example #12
0
 @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 demonstrateSlowProcessing() {
   // #tweets-slow-consumption-dropHead
   tweets
       .buffer(10, OverflowStrategy.dropHead())
       .map(t -> slowComputation(t))
       .runWith(Sink.ignore(), mat);
   // #tweets-slow-consumption-dropHead
 }
Example #14
0
  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));
  }
Example #15
0
  @Test
  public void nonNestedFlow() throws Exception {
    // #non-nested-flow
    Source.single(0)
        .map(i -> i + 1)
        .filter(i -> i != 0)
        .map(i -> i - 2)
        .to(Sink.fold(0, (acc, i) -> acc + i));

    // ... where is the nesting?
    // #non-nested-flow
  }
Example #16
0
  @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));
  }
Example #17
0
  @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);
  }
Example #18
0
 @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"));
 }
Example #19
0
 @Test
 public void closedGraph() throws Exception {
   // #embed-closed
   final RunnableGraph<NotUsed> closed1 = Source.single(0).to(Sink.foreach(System.out::println));
   final RunnableGraph<NotUsed> closed2 =
       RunnableGraph.fromGraph(
           GraphDSL.create(
               builder -> {
                 final ClosedShape embeddedClosed = builder.add(closed1);
                 return embeddedClosed; // Could return ClosedShape.getInstance()
               }));
   // #embed-closed
 }
Example #20
0
  @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);
  }
Example #21
0
  @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));
  }
Example #22
0
 @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
   }
 }
Example #23
0
  @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);
  }
Example #24
0
  @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);
  }
Example #25
0
  @Test
  public void materializedValues() throws Exception {
    // #mat-combine-1
    // Materializes to Promise<BoxedUnit>                                     (red)
    final Source<Integer, CompletableFuture<Optional<Integer>>> source = Source.<Integer>maybe();

    // Materializes to BoxedUnit                                              (black)
    final Flow<Integer, Integer, NotUsed> flow1 = Flow.of(Integer.class).take(100);

    // Materializes to Promise<Option<>>                                     (red)
    final Source<Integer, CompletableFuture<Optional<Integer>>> nestedSource =
        source.viaMat(flow1, Keep.left()).named("nestedSource");
    // #mat-combine-1

    // #mat-combine-2
    // Materializes to BoxedUnit                                              (orange)
    final Flow<Integer, ByteString, NotUsed> flow2 =
        Flow.of(Integer.class).map(i -> ByteString.fromString(i.toString()));

    // Materializes to Future<OutgoingConnection>                             (yellow)
    final Flow<ByteString, ByteString, CompletionStage<OutgoingConnection>> flow3 =
        Tcp.get(system).outgoingConnection("localhost", 8080);

    // Materializes to Future<OutgoingConnection>                             (yellow)
    final Flow<Integer, ByteString, CompletionStage<OutgoingConnection>> nestedFlow =
        flow2.viaMat(flow3, Keep.right()).named("nestedFlow");
    // #mat-combine-2

    // #mat-combine-3
    // Materializes to Future<String>                                         (green)
    final Sink<ByteString, CompletionStage<String>> sink =
        Sink.<String, ByteString>fold("", (acc, i) -> acc + i.utf8String());

    // Materializes to Pair<Future<OutgoingConnection>, Future<String>>       (blue)
    final Sink<Integer, Pair<CompletionStage<OutgoingConnection>, CompletionStage<String>>>
        nestedSink = nestedFlow.toMat(sink, Keep.both());
    // #mat-combine-3

    // #mat-combine-4b
    // Materializes to Future<MyClass>                                        (purple)
    final RunnableGraph<CompletionStage<MyClass>> runnableGraph =
        nestedSource.toMat(nestedSink, Combiner::f);
    // #mat-combine-4b
  }
Example #26
0
 @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);
 }
Example #27
0
  @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 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 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

  }
  @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
    };
  }