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

org.aksw.commons.rx.op.FlowableOperatorConditionalConcat Maven / Gradle / Ivy

There is a newer version: 0.9.9
Show newest version
package org.aksw.commons.rx.op;

import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;

import org.aksw.commons.collector.core.Accumulators;
import org.aksw.commons.collector.domain.Accumulator;
import org.aksw.commons.collector.domain.Aggregator;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.FlowableOperator;
import io.reactivex.rxjava3.core.FlowableSubscriber;
import io.reactivex.rxjava3.internal.subscriptions.SubscriptionHelper;
import io.reactivex.rxjava3.internal.util.BackpressureHelper;


/**
 * Track all seen items of the downstream flowable. When the downstream completes,
 * invoke an action that creates a new publisher based on the seen items that
 * will be concatenated.
 *
 *
 * 
{@code
 * 		Flowable>> list = Flowable
 *			.range(0, 10)
 *			.map(i -> Maps.immutableEntry((int)(i / 3), i))
 *			.lift(FlowableOperatorSequentialGroupBy., Integer, List>create(Entry::getKey, ArrayList::new, (acc, e) -> acc.add(e.getValue())));
 *
 * }
* * @author raven * * @param Item type * @param Group key type * @param Accumulator type */ public final class FlowableOperatorConditionalConcat implements FlowableOperator { /** The amount of items to read ahead */ protected Aggregator aggregator; protected Function> tailFlowFactory; public FlowableOperatorConditionalConcat(Aggregator aggregator, Function> tailFlowFactory) { super(); this.aggregator = aggregator; this.tailFlowFactory = tailFlowFactory; } /** * Create method with the following characteristics: *
    *
  • the accumulator constructor is a mere supplier (and thus neither depends on the accumulator count nor the group Key)
  • *
  • Group keys are compared using Objects::equals
  • *
*/ public static FlowableOperatorConditionalConcat create( Aggregator aggregator, Function> tailFlowFactory) { return new FlowableOperatorConditionalConcat(aggregator, tailFlowFactory); } @Override public Subscriber apply(Subscriber downstream) throws Exception { return new SubscriberImpl(downstream); } /** This subscriber first consumes the initial upstream and caches all seen items. * Afterwards, a new flowable is created from those items and the subscriber attaches itself * to that new flowable. */ public class SubscriberImpl implements FlowableSubscriber, Subscription { protected Subscriber downstream; protected Subscription upstream; protected boolean isInitialUpstreamComplete = false; protected Accumulator accumulator; protected AtomicLong downstreamDemand; public SubscriberImpl(Subscriber downstream) { this.downstream = downstream; this.accumulator = Accumulators.synchronize(aggregator.createAccumulator()); this.downstreamDemand = new AtomicLong(); } @Override public void onSubscribe(Subscription s) { if (upstream != null) { s.cancel(); } else { upstream = s; // Only subscribe to the downstream once if (!isInitialUpstreamComplete) { downstream.onSubscribe(this); } long remainingDemand = downstreamDemand.get(); if (remainingDemand != 0) { upstream.request(remainingDemand); } } } @Override public void onNext(T item) { accumulator.accumulate(item); downstream.onNext(item); downstreamDemand.decrementAndGet(); } /** Called when the upstream completes */ @Override public void onComplete() { if (!isInitialUpstreamComplete) { isInitialUpstreamComplete = true; upstream = null; C accumulatedValue = accumulator.getValue(); Flowable tailFlow = tailFlowFactory.apply(accumulatedValue); if (tailFlow != null) { tailFlow.subscribe(this); } } else { downstream.onComplete(); } } @Override public void onError(Throwable t) { downstream.onError(t); } @Override public void request(long n) { if (SubscriptionHelper.validate(n)) { BackpressureHelper.add(downstreamDemand, n); } } @Override public void cancel() { upstream.cancel(); upstream = SubscriptionHelper.CANCELLED; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy