@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
  }
Beispiel #2
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
  }
Beispiel #3
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
  }
Beispiel #4
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
  }
Beispiel #5
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
  }
  @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));
  }
Beispiel #7
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"));
 }
Beispiel #8
0
  @Test
  public void attributes() throws Exception {
    // #attributes-inheritance
    final Source<Integer, NotUsed> nestedSource =
        Source.single(0).map(i -> i + 1).named("nestedSource"); // Wrap, no inputBuffer set

    final Flow<Integer, Integer, NotUsed> nestedFlow =
        Flow.of(Integer.class)
            .filter(i -> i != 0)
            .via(
                Flow.of(Integer.class)
                    .map(i -> i - 2)
                    .withAttributes(Attributes.inputBuffer(4, 4))) // override
            .named("nestedFlow"); // Wrap, no inputBuffer set

    final Sink<Integer, NotUsed> nestedSink =
        nestedFlow
            .to(Sink.fold(0, (acc, i) -> acc + i)) // wire an atomic sink to the nestedFlow
            .withAttributes(
                Attributes.name("nestedSink").and(Attributes.inputBuffer(3, 3))); // override
    // #attributes-inheritance
  }
  @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));
  }
Beispiel #10
0
  @Test
  public void nestedFlow() throws Exception {
    // #nested-flow
    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

    // Create a RunnableGraph
    final RunnableGraph<NotUsed> runnableGraph = nestedSource.to(nestedSink);
    // #nested-flow
  }
Beispiel #11
0
  // #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());
            }));
  }
Beispiel #12
0
  @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));
  }
Beispiel #13
0
  @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);
  }
Beispiel #14
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));
  }
Beispiel #15
0
  @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));
  }
Beispiel #16
0
  public static void main(String[] args) {

    Outlet<Integer> outlet = null;

    Outlet<Integer> outlet1 = null;
    Outlet<Integer> outlet2 = null;

    Inlet<Integer> inlet = null;

    Inlet<Integer> inlet1 = null;
    Inlet<Integer> inlet2 = null;

    Flow<Integer, Integer, BoxedUnit> flow = Flow.of(Integer.class);
    Flow<Integer, Integer, BoxedUnit> flow1 = Flow.of(Integer.class);
    Flow<Integer, Integer, BoxedUnit> flow2 = Flow.of(Integer.class);

    Promise<Option<Integer>> promise = null;

    {
      Graph<SourceShape<Integer>, BoxedUnit> graphSource = null;
      Graph<SinkShape<Integer>, BoxedUnit> graphSink = null;
      Graph<FlowShape<Integer, Integer>, BoxedUnit> graphFlow = null;

      // #flow-wrap
      Source<Integer, BoxedUnit> source = Source.fromGraph(graphSource);
      Sink<Integer, BoxedUnit> sink = Sink.fromGraph(graphSink);
      Flow<Integer, Integer, BoxedUnit> aflow = Flow.fromGraph(graphFlow);
      Flow.fromSinkAndSource(Sink.<Integer>head(), Source.single(0));
      Flow.fromSinkAndSourceMat(Sink.<Integer>head(), Source.single(0), Keep.left());
      // #flow-wrap

      Graph<BidiShape<Integer, Integer, Integer, Integer>, BoxedUnit> bidiGraph = null;

      // #bidi-wrap
      BidiFlow<Integer, Integer, Integer, Integer, BoxedUnit> bidiFlow =
          BidiFlow.fromGraph(bidiGraph);
      BidiFlow.fromFlows(flow1, flow2);
      BidiFlow.fromFlowsMat(flow1, flow2, Keep.both());
      // #bidi-wrap

    }

    {
      // #graph-create
      GraphDSL.create(
          builder -> {
            // ...
            return ClosedShape.getInstance();
          });

      GraphDSL.create(
          builder -> {
            // ...
            return new FlowShape<>(inlet, outlet);
          });
      // #graph-create
    }

    {
      // #graph-create-2
      GraphDSL.create(
          builder -> {
            // ...
            return SourceShape.of(outlet);
          });

      GraphDSL.create(
          builder -> {
            // ...
            return SinkShape.of(inlet);
          });

      GraphDSL.create(
          builder -> {
            // ...
            return FlowShape.of(inlet, outlet);
          });

      GraphDSL.create(
          builder -> {
            // ...
            return BidiShape.of(inlet1, outlet1, inlet2, outlet2);
          });
      // #graph-create-2
    }

    {
      // #graph-builder
      GraphDSL.create(
          builder -> {
            builder.from(outlet).toInlet(inlet);
            builder.from(outlet).via(builder.add(flow)).toInlet(inlet);
            builder.from(builder.add(Source.single(0))).to(builder.add(Sink.head()));
            // ...
            return ClosedShape.getInstance();
          });
      // #graph-builder
    }

    // #source-creators
    Source<Integer, Promise<Option<Integer>>> src = Source.<Integer>maybe();
    // Complete the promise with an empty option to emulate the old lazyEmpty
    promise.trySuccess(scala.Option.empty());

    final Source<String, Cancellable> ticks =
        Source.tick(
            FiniteDuration.create(0, TimeUnit.MILLISECONDS),
            FiniteDuration.create(200, TimeUnit.MILLISECONDS),
            "tick");

    final Source<Integer, BoxedUnit> pubSource =
        Source.fromPublisher(TestPublisher.<Integer>manualProbe(true, sys));

    final Source<Integer, BoxedUnit> futSource = Source.fromFuture(Futures.successful(42));

    final Source<Integer, Subscriber<Integer>> subSource = Source.<Integer>asSubscriber();
    // #source-creators

    // #sink-creators
    final Sink<Integer, BoxedUnit> subSink =
        Sink.fromSubscriber(TestSubscriber.<Integer>manualProbe(sys));
    // #sink-creators

    // #sink-as-publisher
    final Sink<Integer, Publisher<Integer>> pubSink = Sink.<Integer>asPublisher(false);

    final Sink<Integer, Publisher<Integer>> pubSinkFanout = Sink.<Integer>asPublisher(true);
    // #sink-as-publisher

    // #empty-flow
    Flow<Integer, Integer, BoxedUnit> emptyFlow = Flow.<Integer>create();
    // or
    Flow<Integer, Integer, BoxedUnit> emptyFlow2 = Flow.of(Integer.class);
    // #empty-flow

    // #flatMapConcat
    Flow.<Source<Integer, BoxedUnit>>create()
        .<Integer, BoxedUnit>flatMapConcat(
            new Function<Source<Integer, BoxedUnit>, Source<Integer, BoxedUnit>>() {
              @Override
              public Source<Integer, BoxedUnit> apply(Source<Integer, BoxedUnit> param)
                  throws Exception {
                return param;
              }
            });
    // #flatMapConcat

    Uri uri = null;
    // #raw-query
    final akka.japi.Option<String> theRawQueryString = uri.rawQueryString();
    // #raw-query

    // #query-param
    final akka.japi.Option<String> aQueryParam = uri.query().get("a");
    // #query-param

    // #file-source-sink
    final Source<ByteString, Future<Long>> fileSrc = FileIO.fromFile(new File("."));

    final Source<ByteString, Future<Long>> otherFileSrc = FileIO.fromFile(new File("."), 1024);

    final Sink<ByteString, Future<Long>> fileSink = FileIO.toFile(new File("."));
    // #file-source-sink

    // #input-output-stream-source-sink
    final Source<ByteString, Future<java.lang.Long>> inputStreamSrc =
        StreamConverters.fromInputStream(
            new Creator<InputStream>() {
              public InputStream create() {
                return new SomeInputStream();
              }
            });

    final Source<ByteString, Future<java.lang.Long>> otherInputStreamSrc =
        StreamConverters.fromInputStream(
            new Creator<InputStream>() {
              public InputStream create() {
                return new SomeInputStream();
              }
            },
            1024);

    final Sink<ByteString, Future<java.lang.Long>> outputStreamSink =
        StreamConverters.fromOutputStream(
            new Creator<OutputStream>() {
              public OutputStream create() {
                return new SomeOutputStream();
              }
            });
    // #input-output-stream-source-sink

    // #output-input-stream-source-sink
    final FiniteDuration timeout = FiniteDuration.Zero();

    final Source<ByteString, OutputStream> outputStreamSrc = StreamConverters.asOutputStream();

    final Source<ByteString, OutputStream> otherOutputStreamSrc =
        StreamConverters.asOutputStream(timeout);

    final Sink<ByteString, InputStream> someInputStreamSink = StreamConverters.asInputStream();

    final Sink<ByteString, InputStream> someOtherInputStreamSink =
        StreamConverters.asInputStream(timeout);
    // #output-input-stream-source-sink

  }