@Override public void subscribe(CoreSubscriber<? super O> actual) { CoreSubscriber<? super I> input = lifter.apply(source, actual); Objects.requireNonNull(input, "Lifted subscriber MUST NOT be null"); source.subscribe(input); } }
@Override public void subscribe(CoreSubscriber<? super O> actual) { CoreSubscriber<? super I> input = lifter.apply(source, actual); Objects.requireNonNull(input, "Lifted subscriber MUST NOT be null"); if (actual instanceof QueueSubscription && !(input instanceof QueueSubscription)) { //user didn't produce a QueueSubscription, original was one input = new FluxHide.SuppressFuseableSubscriber<>(input); } //otherwise QS is not required or user already made a compatible conversion source.subscribe(input); } }
@Override public void subscribe(CoreSubscriber<? super T> actual) { source.subscribe(actual); if (remaining > 0 && REMAINING.decrementAndGet(this) == 0) { source.connect(cancelSupport); } }
@Override public void subscribe(CoreSubscriber<? super T> actual) { source.subscribe(actual); if (remaining > 0 && REMAINING.decrementAndGet(this) == 0) { source.connect(cancelSupport); } }
@Override public void subscribe(CoreSubscriber<? super T> actual) { RefCountMonitor<T> conn; boolean connect = false; synchronized (this) { conn = connection; if (conn == null || conn.terminated) { conn = new RefCountMonitor<>(this); connection = conn; } long c = conn.subscribers; conn.subscribers = c + 1; if (!conn.connected && c + 1 == n) { connect = true; conn.connected = true; } } source.subscribe(new RefCountInner<>(actual, conn)); if (connect) { source.connect(conn); } }
@Test public void advancedConnectable() throws InterruptedException { Flux<Integer> source = Flux.range(1, 3) .doOnSubscribe(s -> System.out.println("subscribed to source")); ConnectableFlux<Integer> co = source.publish(); co.subscribe(System.out::println, e -> {}, () -> {}); co.subscribe(System.out::println, e -> {}, () -> {}); System.out.println("done subscribing"); Thread.sleep(500); System.out.println("will now connect"); co.connect(); }
@Override public void subscribe(CoreSubscriber<? super T> actual) { RefConnection conn; boolean connect = false; synchronized (this) { conn = connection; if (conn == null || conn.terminated) { conn = new RefConnection(this); connection = conn; } long c = conn.subscriberCount; if (c == 0L && conn.timer != null) { conn.timer.dispose(); } conn.subscriberCount = c + 1; if (!conn.connected && c + 1 == n) { connect = true; conn.connected = true; } } source.subscribe(new RefCountInner<>(actual, this, conn)); if (connect) { source.connect(conn); } }
@Test public void cancel() { ConnectableFlux<Integer> replay = UnicastProcessor.<Integer>create() .replay(2); replay.subscribe(v -> {}, e -> { throw Exceptions.propagate(e); }); Disposable connected = replay.connect(); //the lambda subscriber itself is cancelled so it will bubble the exception //propagated by connect().dispose() assertThatExceptionOfType(RuntimeException.class) .isThrownBy(connected::dispose) .withMessage("Disconnected"); boolean cancelled = ((FluxReplay.ReplaySubscriber) connected).cancelled; assertThat(cancelled).isTrue(); }
@Test public void fusedMapInvalid() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); ConnectableFlux<Integer> p = Flux.range(1, 5).map(v -> (Integer)null).publish(); p.subscribe(ts); p.connect(); ts.assertNoValues() .assertError(NullPointerException.class) .assertNotComplete(); }
@Test public void error() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); EmitterProcessor<Integer> e = EmitterProcessor.create(); ConnectableFlux<Integer> p = e.publish(); p.subscribe(ts); p.connect(); e.onNext(1); e.onNext(2); e.onError(new RuntimeException("forced failure")); ts.assertValues(1, 2) .assertError(RuntimeException.class) .assertErrorWith( x -> Assert.assertTrue(x.getMessage().contains("forced failure"))) .assertNotComplete(); }
@Test public void disconnectBackpressured() { AssertSubscriber<Integer> ts = AssertSubscriber.create(0); EmitterProcessor<Integer> e = EmitterProcessor.create(); ConnectableFlux<Integer> p = e.publish(); p.subscribe(ts); Disposable r = p.connect(); r.dispose(); ts.assertNoValues() .assertError(CancellationException.class) .assertNotComplete(); Assert.assertFalse("sp has subscribers?", e.downstreamCount() != 0); }
@Test public void normalSyncFused() { AssertSubscriber<Integer> ts1 = AssertSubscriber.create(); AssertSubscriber<Integer> ts2 = AssertSubscriber.create(); ConnectableFlux<Integer> p = Flux.range(1, 5).publish(5); p.subscribe(ts1); p.subscribe(ts2); ts1 .assertNoValues() .assertNoError() .assertNotComplete(); ts2 .assertNoValues() .assertNoError() .assertNotComplete(); p.connect(); ts1.assertValues(1, 2, 3, 4, 5) .assertNoError() .assertComplete(); ts2.assertValues(1, 2, 3, 4, 5) .assertNoError() .assertComplete(); }
@Test public void normal() { AssertSubscriber<Integer> ts1 = AssertSubscriber.create(); AssertSubscriber<Integer> ts2 = AssertSubscriber.create(); ConnectableFlux<Integer> p = Flux.range(1, 5).hide().publish(); p.subscribe(ts1); p.subscribe(ts2); ts1 .assertNoValues() .assertNoError() .assertNotComplete(); ts2 .assertNoValues() .assertNoError() .assertNotComplete(); p.connect(); ts1.assertValues(1, 2, 3, 4, 5) .assertNoError() .assertComplete(); ts2.assertValues(1, 2, 3, 4, 5) .assertNoError() .assertComplete(); }
@Test public void disconnect() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); EmitterProcessor<Integer> e = EmitterProcessor.create(); ConnectableFlux<Integer> p = e.publish(); p.subscribe(ts); Disposable r = p.connect(); e.onNext(1); e.onNext(2); r.dispose(); ts.assertValues(1, 2) .assertError(CancellationException.class) .assertNotComplete(); Assert.assertFalse("sp has subscribers?", e.downstreamCount() != 0); }
@Test public void normalAsyncFused() { AssertSubscriber<Integer> ts1 = AssertSubscriber.create(); AssertSubscriber<Integer> ts2 = AssertSubscriber.create(); UnicastProcessor<Integer> up = UnicastProcessor.create(Queues.<Integer>get(8).get()); up.onNext(1); up.onNext(2); up.onNext(3); up.onNext(4); up.onNext(5); up.onComplete(); ConnectableFlux<Integer> p = up.publish(); p.subscribe(ts1); p.subscribe(ts2); ts1 .assertNoValues() .assertNoError() .assertNotComplete(); ts2 .assertNoValues() .assertNoError() .assertNotComplete(); p.connect(); ts1.assertValues(1, 2, 3, 4, 5) .assertNoError() .assertComplete(); ts2.assertValues(1, 2, 3, 4, 5) .assertNoError() .assertComplete(); }
@Override public void subscribe(CoreSubscriber<? super O> actual) { CoreSubscriber<? super I> input = lifter.apply(source, actual); Objects.requireNonNull(input, "Lifted subscriber MUST NOT be null"); source.subscribe(input); } }
@Override public void subscribe(CoreSubscriber<? super T> actual) { source.subscribe(actual); if (remaining > 0 && REMAINING.decrementAndGet(this) == 0) { source.connect(cancelSupport); } }