@Override public void subscribe(Flow.Subscriber<? super DataChunk> originalSubscriber) { if (!hasSingleSubscriber.compareAndSet(false, true)) { originalSubscriber.onError(new IllegalStateException("Only single subscriber is allowed!")); return; originalSubscriber.onSubscribe(new Flow.Subscription() {
singleSubscriber.onNext(item); } finally { nexting = false; } 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."); singleSubscriber.onComplete(); } else if (queue.isEmpty()) { long released = n == Long.MAX_VALUE ? Long.MAX_VALUE : release;
@Override public void subscribe(Flow.Subscriber<? super DataChunk> originalSubscriber) { if (!hasSingleSubscriber.compareAndSet(false, true)) { originalSubscriber.onError(new IllegalStateException("Only single subscriber is allowed!")); return; originalSubscriber.onSubscribe(new Flow.Subscription() {
subscr.onNext(chunk); } else { curentChunk = chunk;
singleSubscriber.onNext(item); } finally { nexting = false; } 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."); singleSubscriber.onComplete(); } else if (queue.isEmpty()) { long released = n == Long.MAX_VALUE ? Long.MAX_VALUE : release;
singleSubscriber.onNext(item); } else { LOGGER.finest(() -> "Not publishing due to low request count: " + nextCount + " <= " + reqCount);
subscriber.onError(new IllegalStateException("Multiple subscribers aren't allowed!")); return; this.singleSubscriber.onSubscribe(new Flow.Subscription() { @Override public void request(long n) {
@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.onSubscribe(subscribersSubscription);
/** * 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; } }
private void publish(byte[] buffer, int offset, int length) throws IOException { Objects.requireNonNull(buffer); try { final Flow.Subscriber<? super ByteBuffer> sub = subscriber.get(); while (!subscriber.isClosed() && !requested.tryDecrement()) { //java9 //Thread.onSpinWait(); // wait until some data can be sent or the stream has been closed //java8 :( Thread.sleep(30); } synchronized (invocationLock) { if (subscriber.isClosed()) { throw new IOException("Output stream already closed."); } sub.onNext(ByteBuffer.wrap(buffer, offset, length)); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); complete(e); throw new IOException(e); } catch (ExecutionException e) { complete(e.getCause()); throw new IOException(e.getCause()); } }
@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(); } } }
/** * 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(); } }
@Override public void subscribe(Flow.Subscriber<? super DataChunk> subscriberParam) { if (subscriber.register(subscriberParam)) { publishing.set(true); // prevent onNext from inside of onSubscribe try { subscriberParam.onSubscribe(new Flow.Subscription() { @Override public void request(long n) { requested.increment(n, t -> tryComplete(t)); tryPublish(); } @Override public void cancel() { subscriber.cancel(); } }); } finally { publishing.set(false); } tryPublish(); // give onNext a chance in case request has been invoked in onSubscribe } }
private void publish(byte[] buffer, int offset, int length) throws IOException { Objects.requireNonNull(buffer); try { final Flow.Subscriber<? super ByteBuffer> sub = subscriber.get(); while (!subscriber.isClosed() && !requested.tryDecrement()) { Thread.sleep(250); // wait until some data can be sent or the stream has been closed } synchronized (invocationLock) { if (subscriber.isClosed()) { throw new IOException("Output stream already closed."); } sub.onNext(ByteBuffer.wrap(buffer, offset, length)); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); complete(e); throw new IOException(e); } catch (ExecutionException e) { complete(e.getCause()); throw new IOException(e.getCause()); } }
private void tryPublish() { while (!subscriber.isClosed() && (requested.get() > 0) && publishing.compareAndSet(false, true)) { try { final Flow.Subscriber<? super ByteBuffer> sub = this.subscriber.get(); // blocking retrieval while (!subscriber.isClosed() && requested.tryDecrement()) { int len = inputStream.read(buffer); if (len >= 0) { sub.onNext(ByteBuffer.wrap(buffer, 0, len)); } else { tryComplete(); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); tryComplete(e); } catch (IOException | ExecutionException e) { tryComplete(e); } finally { publishing.set(false); // give a chance to some other thread to publish } } }
@Override public void subscribe(Flow.Subscriber<? super ByteBuffer> subscriberParam) { if (subscriber.register(subscriberParam)) { publishing.set(true); // prevent onNext from inside of onSubscribe try { subscriberParam.onSubscribe(new Flow.Subscription() { @Override public void request(long n) { requested.increment(n, t -> tryComplete(t)); tryPublish(); } @Override public void cancel() { } }); } finally { publishing.set(false); } tryPublish(); // give onNext a chance in case request has been invoked in onSubscribe } }
/** * Synchronously trigger {@link Flow.Subscriber#onComplete()}. */ void complete() { try { reentrantLock.lock(); completed = true; if (singleSubscriber != null && queue.isEmpty()) { LOGGER.finest("Completing by the producing thread."); singleSubscriber.onComplete(); singleSubscriber = null; } else { LOGGER.finest("Not completing by the producing thread."); } } finally { reentrantLock.unlock(); referenceQueue.release(); } }
@Override public void subscribe(Flow.Subscriber<? super ByteBuffer> subscriberParam) { if (subscriber.register(subscriberParam)) { subscriberParam.onSubscribe(new Flow.Subscription() { @Override public void request(long n) { requested.increment(n, t -> complete(t)); } @Override public void cancel() { subscriber.cancel(); } }); } }
@Override public void onError(Throwable throwable) { delegate.onError(throwable); }