/** * Register a new subscriber. * <p> * In case the subscriber registration fails (e.g. the holder already holds a previously registered subscriber * or the holder has been {@link #close(Consumer) closed}), the newly registered subscriber is notified about the * error by invoking it's {@link io.helidon.common.reactive.Flow.Subscriber#onError(Throwable) subscriber.onError} method. * * @param subscriber subscriber to be registered in the holder. * @return {@code true} if the subscriber was successfully registered, {@code false} otherwise. */ public boolean register(Flow.Subscriber<? super T> subscriber) { if (this.subscriber.complete(subscriber)) { return true; } else { Throwable error = null; try { this.subscriber.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); error = e; } catch (ExecutionException e) { error = e.getCause(); } subscriber.onError(error != null ? error : new IllegalStateException("This publisher only supports a single subscriber!")); return false; } }
/** * Register a new subscriber. * <p> * In case the subscriber registration fails (e.g. the holder already holds a previously registered subscriber * or the holder has been {@link #close(Consumer) closed}), the newly registered subscriber is notified about the * error by invoking it's {@link Flow.Subscriber#onError(Throwable) subscriber.onError} method. * * @param subscriber subscriber to be registered in the holder. * @return {@code true} if the subscriber was successfully registered, {@code false} otherwise. */ public boolean register(Flow.Subscriber<? super T> subscriber) { if (!this.subscriber.complete(subscriber)) { Throwable error = null; try { this.subscriber.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); error = e; } catch (ExecutionException e) { error = e.getCause(); } subscriber.onError((error != null) ? error : new IllegalStateException( "This publisher only supports a single subscriber.")); return false; } return true; }
/** * Synchronously trigger {@link io.helidon.common.reactive.Flow.Subscriber#onError(Throwable)}. * * @param throwable the exception to send */ void error(Throwable throwable) { try { reentrantLock.lock(); if (singleSubscriber != null && queue.isEmpty()) { singleSubscriber.onError(throwable); singleSubscriber = null; } else { t = throwable; } } catch (RuntimeException e) { // throwable consumption emitted another exception throw new IllegalStateException("On error threw an exception!", e); } finally { reentrantLock.unlock(); referenceQueue.release(); } }
} else if (t != null) { LOGGER.finest("Completing with an error from request."); singleSubscriber.onError(t); } else if (completed && queue.isEmpty()) { LOGGER.finest("Completing from request.");
@Override public void subscribe(Flow.Subscriber<? super R> subscriber) { if (!isSubscribed.compareAndSet(false, true)) { subscriber.onError(new IllegalStateException("This publisher only supports a single subscriber.")); return;
subscriber.onError(new IllegalArgumentException("Unexpected exception occurred during publishers chaining", e));
@Override public void request(long n) { if (n <= 0) { subscriber.onError(new IllegalArgumentException("Requested illegal item count: " + 0)); return; } if (pausableFeeder != null) { // a standard release pausableFeeder.release(n); } else { try { pausableFeederNullLock.lock(); if (pausableFeeder == null) { // the first item is always emitted, as such we set one less pausableFeeder = new PausableFeeder(n - 1, valve); handleValve(); } else { // pausableFeeder actually is not null, do a standard release pausableFeeder.release(n); } } finally { pausableFeederNullLock.unlock(); } } }
@Override public void subscribe(Flow.Subscriber<? super T> subscriber) { // Register ONLY single subscriber boolean hasSubscriber = singleSubscriber != null; if (!hasSubscriber) { synchronized (lock) { // Potentially can be registered hasSubscriber = singleSubscriber != null; if (!hasSubscriber) { this.singleSubscriber = subscriber; } } } if (hasSubscriber) { subscriber.onError(new IllegalStateException("Only single subscriber is allowed!")); return; } DelegatingSubscriber ds = new DelegatingSubscriber(subscriber); delegate.subscribe(ds); }
@Override public void onError(Throwable t) { subscriber.onError(t); }
@Override public void onError(Throwable throwable) { subscriber.onError(throwable); }
@Override public void onError(Throwable throwable) { delegate.onError(throwable); }
private void tryComplete(Throwable t) { subscriber.close(sub -> sub.onError(t)); }
@Override public void onError(Throwable throwable) { delegate.onError(throwable); }
@Override public void onError(Throwable throwable) { delegate.onError(throwable); }
@Override public void onError(Throwable throwable) { delegate.onError(throwable); }
private void tryComplete(Throwable t) { subscriber.close(sub -> sub.onError(t)); } }
@Override public void subscribe(Flow.Subscriber<? super DataChunk> subscriber) { subscriber.onError(new UnsupportedOperationException("Subscribing on this publisher is not allowed!")); }
private void handleValve() { valve.handle((data) -> { singleSubscriber.onNext(data); pausableFeeder.acquire(); }, throwable -> singleSubscriber.onError(new IllegalStateException( "Valve to Publisher in an error.", throwable)), singleSubscriber::onComplete); }
private void complete(Throwable t) { subscriber.close(sub -> { synchronized (invocationLock) { sub.onError(t); } }); } }
private void complete(Throwable t) { subscriber.close(sub -> { synchronized (invocationLock) { sub.onError(t); } }); } }