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 }
/** * 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); }
@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); }
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); } }; } }
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")); } }; } }
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(); } }
@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 } }
@BeforeClass public static void setup() { system = ActorSystem.create("CompositionDocTest"); mat = ActorMaterializer.create(system); }