// #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; } } }; } }
// #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()); } }
// #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); } }; } }
// #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); } } }); } }; } }
// #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); } }); } }; } }
// #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); } }); } }; } }
// #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()); })); }
// #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); } }); } }; } }
// #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); } } }); } }; } }
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 }