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

reactor.rx.action.control.DispatcherAction Maven / Gradle / Ivy

There is a newer version: 2.0.8.RELEASE
Show newest version
/*
 * Copyright (c) 2011-2015 Pivotal Software Inc, All Rights Reserved.
 *
 * 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.action.control;

import org.reactivestreams.Subscription;
import reactor.core.Dispatcher;
import reactor.core.dispatch.SynchronousDispatcher;
import reactor.core.dispatch.TailRecurseDispatcher;
import reactor.fn.Consumer;
import reactor.rx.action.Action;
import reactor.rx.subscription.PushSubscription;

import java.util.concurrent.atomic.AtomicLongFieldUpdater;

/**
 * @author Stephane Maldini
 * @since 2.0
 */
public final class DispatcherAction extends Action {

	private final Dispatcher dispatcher;
	private final Dispatcher requestDispatcher;

	private volatile long pendingRequests = 0l;

	private final AtomicLongFieldUpdater PENDING_UPDATER =
			AtomicLongFieldUpdater.newUpdater(DispatcherAction.class, "pendingRequests");


	public DispatcherAction(Dispatcher dispatcher, Dispatcher requestDispatcher) {
		this.dispatcher = dispatcher;
		this.requestDispatcher = requestDispatcher != SynchronousDispatcher.INSTANCE ? dispatcher : requestDispatcher;
	}

	@Override
	public boolean isReactivePull(Dispatcher dispatcher, long producerCapacity) {
		return this.dispatcher != dispatcher;
	}

	@Override
	protected void doOnSubscribe(Subscription subscription) {
		long toRequest = PENDING_UPDATER.getAndSet(this, 0l);
		if (toRequest > 0l) {
			requestMore(toRequest);
		}
	}


	@Override
	protected void requestUpstream(long capacity, boolean terminated, long elements) {
		requestMore(elements);
	}

	@Override
	public void requestMore(long n) {
		Action.checkRequest(n);
		long toRequest = n != Long.MAX_VALUE ? Math.min(capacity, n) : Long.MAX_VALUE;
		PushSubscription upstreamSubscription = this.upstreamSubscription;

		if (upstreamSubscription != null) {
			toRequest = toRequest - Math.max(upstreamSubscription.pendingRequestSignals(), 0l);
			toRequest = toRequest < 0l ? 0l : toRequest;

			if (n == Long.MAX_VALUE || PENDING_UPDATER.addAndGet(this, n - toRequest) < 0l) {
				PENDING_UPDATER.set(this, Long.MAX_VALUE);
			}

			if (toRequest > 0) {
				if(requestDispatcher.inContext()) {
					requestDispatcher.dispatch(toRequest, upstreamSubscription, null);
				}else if (requestDispatcher == SynchronousDispatcher.INSTANCE){
					TailRecurseDispatcher.INSTANCE.dispatch(toRequest, upstreamSubscription, null);
				}else{
					upstreamSubscription.request(toRequest);
				}
			}
		} else {
			if (n == Long.MAX_VALUE || PENDING_UPDATER.addAndGet(this, n) < 0l) {
				PENDING_UPDATER.set(this, Long.MAX_VALUE);
			}
		}

	}


	/*
	@Override
	public void requestMore(final long n) {
		checkRequest(n);
		try{
			dispatcher.tryDispatch(n, upstreamSubscription, null);
		}catch(InsufficientCapacityException s){
			Environment environment = getEnvironment();
			environment = environment == null && Environment.alive() ? Environment.get() : null;
			if(environment != null){
				environment.getTimer().submit(new Consumer() {
					@Override
					public void accept(Long aLong) {
						dispatcher.tryDispatch(n, upstreamSubscription, null);
					}
				});
			}
		}
	}*/

/*
	@Override
	protected void doStart(final long n) {
		if(dispatcher.inContext()){
			super.doStart(n);
		} else {
			dispatcher.dispatch(null, new Consumer() {
				@Override
				public void accept(Void aVoid) {
					DispatcherAction.super.doStart(n);
				}
			}, null);
		}
	}*/

	@Override
	public void onNext(T ev) {
		if(ev == null){
			throw new NullPointerException("Spec 2.13: Signal cannot be null");
		}
		if (dispatcher.inContext()) {
			super.onNext(ev);
		} else {
			dispatcher.dispatch(ev, this, null);
		}
	}

	@Override
	public void onError(Throwable cause) {
		if(cause == null){
			throw new NullPointerException("Spec 2.13: Signal cannot be null");
		}
		if (dispatcher.inContext()) {
			super.onError(cause);
		} else {
			dispatcher.dispatch(cause, new Consumer() {
				@Override
				public void accept(Throwable throwable) {
					DispatcherAction.super.onError(throwable);
				}
			}, null);
		}
	}

	@Override
	public void onComplete() {
		if (dispatcher.inContext()) {
			super.onComplete();
		} else {
			dispatcher.dispatch(null, new Consumer() {
				@Override
				public void accept(Void aVoid) {
					DispatcherAction.super.onComplete();
				}
			}, null);
		}
	}

	@Override
	protected void doNext(T ev) {
		broadcastNext(ev);
		long toRequest;
		PushSubscription sub = upstreamSubscription;
		if (sub != null && pendingRequests != Long.MAX_VALUE &&
				sub.pendingRequestSignals() == 0l &&
				(toRequest = PENDING_UPDATER.getAndSet(this, 0l)) > 0l) {
			requestMore(toRequest);
		}
	}

	@Override
	public Dispatcher getDispatcher() {
		return dispatcher;
	}

	@Override
	public String toString() {
		return super.toString() + "{overflow=" + pendingRequests + "}";
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy