All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mutiny.zero.operators.Concatenate Maven / Gradle / Ivy

Go to download

Mutiny Zero is a minimal API for creating reactive-streams compliant publishers

There is a newer version: 1.1.1
Show newest version
package mutiny.zero.operators;

import static java.util.Objects.requireNonNull;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Flow;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import mutiny.zero.internal.Helper;

/**
 * A {@link java.util.concurrent.Flow.Publisher} that is the concatenation of several ones.
 * 

* The first publisher in the list is the first to be subscribed. * Once it completes the next one is subscribed and so on, up to the completion of the last one. *

* If any publisher sends an error signal then the concatenation stream ends with that error. * * @param the elements type */ public class Concatenate implements Flow.Publisher { private final List> publishers; /** * Create a new concatenation publisher. * * @param publishers the list of publishers, must not be {@code null}, must not contain {@code null} */ public Concatenate(List> publishers) { this.publishers = requireNonNull(publishers, "The publishers list cannot be null"); for (Flow.Publisher publisher : publishers) { requireNonNull(publisher, "A publisher cannot be null"); } } @Override public void subscribe(Flow.Subscriber subscriber) { requireNonNull(subscriber, "The subscriber cannot be null"); Processor processor = new Processor(); processor.subscribe(subscriber); } private class Processor implements Flow.Processor, Flow.Subscription { private Flow.Subscriber downstream; private Flow.Subscription upstreamSubscription; private final AtomicBoolean cancelled = new AtomicBoolean(); private final AtomicLong demand = new AtomicLong(); private volatile boolean unboundedDemand; private boolean downstreamIsReady; private final Iterator> publisherIterator = publishers.iterator(); @Override public void subscribe(Flow.Subscriber subscriber) { downstream = subscriber; subscribeNext(); } private void subscribeNext() { if (publisherIterator.hasNext()) { Flow.Publisher publisher = publisherIterator.next(); publisher.subscribe(this); } else { downstream.onComplete(); } } @Override public void onSubscribe(Flow.Subscription subscription) { if (cancelled.get()) { return; } this.upstreamSubscription = subscription; if (downstreamIsReady) { long n = demand.get(); if (n > 0L) { this.upstreamSubscription.request(n); } } else { downstreamIsReady = true; downstream.onSubscribe(this); } } @Override public void onNext(T item) { if (!cancelled.get()) { if (!unboundedDemand) { demand.decrementAndGet(); } downstream.onNext(item); } } @Override public void onError(Throwable throwable) { if (!cancelled.get()) { cancel(); downstream.onError(throwable); } } @Override public void onComplete() { if (!cancelled.get()) { subscribeNext(); } } @Override public void request(long n) { if (cancelled.get()) { return; } if (n <= 0L) { onError(Helper.negativeRequest(n)); } else { Helper.add(demand, n); if (n == Long.MAX_VALUE) { unboundedDemand = true; } upstreamSubscription.request(n); } } @Override public void cancel() { if (cancelled.compareAndSet(false, true)) { upstreamSubscription.cancel(); upstreamSubscription = null; } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy