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

reactor.rx.subscription.PushSubscription Maven / Gradle / Ivy

There is a newer version: 2.0.8.RELEASE
Show newest version
/*
 * Copyright (c) 2011-2014 Pivotal Software, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package reactor.rx.subscription;

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.fn.Consumer;
import reactor.rx.Stream;
import reactor.rx.subscription.support.WrappedSubscription;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;

/**
 * Relationship between a Stream (Publisher) and a Subscriber. A PushSubscription offers common facilities to track
 * downstream demand. Subclasses such as ReactiveSubscription implement these mechanisms to prevent Subscriber overrun.
 * 

* In Reactor, a subscriber can be an Action which is both a Stream (Publisher) and a Subscriber. * * @author Stephane Maldini */ public class PushSubscription implements Subscription, Consumer { protected final Subscriber subscriber; protected final Stream publisher; protected volatile int terminated = 0; protected static final AtomicIntegerFieldUpdater TERMINAL_UPDATER = AtomicIntegerFieldUpdater .newUpdater(PushSubscription.class, "terminated"); protected volatile long pendingRequestSignals = 0l; protected static final AtomicLongFieldUpdater PENDING_UPDATER = AtomicLongFieldUpdater .newUpdater(PushSubscription.class, "pendingRequestSignals"); /** * Wrap the subscription behind a push subscription to start tracking its requests * * @param subscription the subscription to wrap * @return the new ReactiveSubscription */ public static PushSubscription wrap(Subscription subscription, Subscriber errorSubscriber) { return new WrappedSubscription(subscription, errorSubscriber); } public PushSubscription(Stream publisher, Subscriber subscriber) { this.subscriber = subscriber; this.publisher = publisher; } @Override public final void accept(Long n) { request(n); } @Override public void request(long n) { try { if(publisher == null) { if (pendingRequestSignals != Long.MAX_VALUE && PENDING_UPDATER.addAndGet(this, n) < 0) PENDING_UPDATER.set(this, Long.MAX_VALUE); } if(terminated == -1L){ pendingRequestSignals = n; return; } onRequest(n); } catch (Throwable t) { onError(t); } } @Override public void cancel() { TERMINAL_UPDATER.set(this, 1); if (publisher != null) { publisher.cancelSubscription(this); } } public boolean terminate(){ return TERMINAL_UPDATER.compareAndSet(this, 0, 1); } public void onComplete() { if (TERMINAL_UPDATER.compareAndSet(this, 0, 1) && subscriber != null) { subscriber.onComplete(); } } public void onNext(O ev) { // if (terminated == 0) { subscriber.onNext(ev); // } } public void onError(Throwable throwable) { if (TERMINAL_UPDATER.compareAndSet(this, 0, 1) && subscriber != null) { subscriber.onError(throwable); } } public Stream getPublisher() { return publisher; } public boolean hasPublisher() { return publisher != null; } public void updatePendingRequests(long n) { long oldPending; long newPending; do{ oldPending = pendingRequestSignals; newPending = n == 0l ? 0l : oldPending + n; if(newPending < 0) { newPending = n > 0 ? Long.MAX_VALUE : 0; } }while(!PENDING_UPDATER.compareAndSet(this, oldPending, newPending)); } public void start(){ if(subscriber != null && terminated == -1L){ subscriber.onSubscribe(this); if(markAsStarted() && pendingRequestSignals > 0L){ onRequest(pendingRequestSignals); } } } public final boolean markAsStarted(){ return TERMINAL_UPDATER.compareAndSet(this, -1, 0); } public final boolean markAsDeferredStart(){ return TERMINAL_UPDATER.compareAndSet(this, 0, -1); } protected void onRequest(long n) { //IGNORE, full push } public final Subscriber getSubscriber() { return subscriber; } public boolean isComplete() { return terminated == 1; } public final long pendingRequestSignals() { return pendingRequestSignals; } public void maxCapacity(long n) { /* Adjust capacity (usually the number of elements to be requested at most) */ } public boolean shouldRequestPendingSignals() { /* Should request the next batch of pending signals. Usually when current next signals reaches some limit like the maxCapacity. */ return false; } @Override public int hashCode() { int result = subscriber.hashCode(); if(publisher != null){ result = 31 * result + publisher.hashCode(); } return result; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PushSubscription that = (PushSubscription) o; if (publisher != null && publisher.hashCode() != that.publisher.hashCode()) return false; if (!subscriber.equals(that.subscriber)) return false; return true; } @Override public String toString() { return "{push"+ (pendingRequestSignals > 0 && pendingRequestSignals != Long.MAX_VALUE ? ",pending="+pendingRequestSignals : "") +"}"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy