All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
reactor.rx.action.combination.ZipAction Maven / Gradle / Ivy
/*
* 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.action.combination;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.Dispatcher;
import reactor.fn.Function;
import reactor.fn.tuple.Tuple;
import reactor.rx.subscription.PushSubscription;
import java.util.Arrays;
import java.util.List;
/**
* @author Stephane Maldini
* @since 2.0
*/
public final class ZipAction
extends FanInAction, V, ZipAction.InnerSubscriber> {
private static final Object EMPTY_ZIPPED_DATA = new Object();
final Function accumulator;
int index = 0;
int count = 0;
Object[] toZip = new Object[1];
@SuppressWarnings("unchecked")
public static Function> joinZipper() {
return new Function>() {
@Override
public List apply(TUPLE ts) {
return Arrays.asList((V[]) ts.toArray());
}
};
}
public ZipAction(Dispatcher dispatcher,
Function accumulator, Iterable extends Publisher extends O>>
composables) {
super(dispatcher, composables);
this.accumulator = accumulator;
}
@SuppressWarnings("unchecked")
protected void broadcastTuple(boolean isFinishing) {
long capacity = this.capacity;
if (count >= capacity) {
if (!checkAllFilled()) return;
count = 0;
Object[] _toZip = toZip;
toZip = new Object[toZip.length];
V res = accumulator.apply((TUPLE) Tuple.of(_toZip));
if (res != null) {
broadcastNext(res);
if (!isFinishing && upstreamSubscription.pendingRequestSignals() > 0) {
dispatcher.dispatch(capacity, upstreamSubscription, null);
}
}
}
}
private boolean checkAllFilled() {
for (int i = 0; i < toZip.length; i++) {
if (toZip[i] == null) {
return false;
}
}
return true;
}
@Override
protected FanInSubscription, V, InnerSubscriber> createFanInSubscription() {
return new ZipSubscription(this);
}
@Override
protected PushSubscription> createTrackingSubscription(Subscription subscription) {
return innerSubscriptions;
}
@Override
protected void doNext(Zippable ev) {
count++;
toZip[ev.index] = ev.data == null ? EMPTY_ZIPPED_DATA : ev.data;
broadcastTuple(false);
}
@Override
public void scheduleCompletion() {
//let the zip logic complete
}
@Override
protected void doComplete() {
broadcastTuple(true);
//can receive multiple queued complete signals
super.doComplete();
}
@Override
protected InnerSubscriber createSubscriber() {
int newSize = innerSubscriptions.runningComposables + 1;
capacity(newSize);
if (newSize > toZip.length) {
Object[] previousZip = toZip;
toZip = new Object[newSize];
System.arraycopy(previousZip, 0, toZip, 0, newSize - 1);
}
return new ZipAction.InnerSubscriber<>(this, index++);
}
@Override
protected long initUpstreamPublisherAndCapacity() {
long i = 0l;
for (Publisher extends O> composable : publishers) {
addPublisher(composable);
i++;
}
return i;
}
@Override
public String toString() {
String formatted = super.toString();
for (int i = 0; i < toZip.length; i++) {
if (toZip[i] != null)
formatted += "(" + (i) + "):" + toZip[i] + ",";
}
return formatted.substring(0, count > 0 ? formatted.length() - 1 : formatted.length());
}
//Handling each new Publisher to zip
public static final class InnerSubscriber extends FanInAction.InnerSubscriber, V> {
final ZipAction outerAction;
final int index;
InnerSubscriber(ZipAction outerAction, int index) {
super(outerAction);
this.index = index;
this.outerAction = outerAction;
}
@Override
@SuppressWarnings("unchecked")
public void onSubscribe(Subscription subscription) {
setSubscription(new FanInSubscription.InnerSubscription, InnerSubscriber>(subscription,
this));
if (pendingRequests > 0) {
request(1);
}
if (outerAction.dynamicMergeAction != null) {
outerAction.dynamicMergeAction.decrementWip();
}
}
@Override
public void request(long n) {
super.request(1);
}
@Override
public void onNext(O ev) {
if (--pendingRequests > 0) pendingRequests = 0l;
//emittedSignals++;
outerAction.innerSubscriptions.serialNext(new Zippable(index, ev));
if(outerAction.toZip[index] != null && outerAction.status.get() == COMPLETING){
onComplete();
}
}
@Override
public boolean isReactivePull(Dispatcher dispatcher, long producerCapacity) {
return true;
}
@Override
public long getCapacity() {
return 1;
}
@Override
public String toString() {
return "Zip.InnerSubscriber{index=" + index + ", " +
"pending=" + pendingRequests + ", emitted=" + emittedSignals + "}";
}
}
private final class ZipSubscription extends FanInSubscription, V, ZipAction.InnerSubscriber> {
public ZipSubscription(Subscriber super Zippable> subscriber) {
super(subscriber);
}
@Override
public boolean shouldRequestPendingSignals() {
synchronized (this) {
return pendingRequestSignals > 0 && pendingRequestSignals != Long.MAX_VALUE && count == maxCapacity;
}
}
@Override
public void request(long elements) {
if (pendingRequestSignals == Long.MAX_VALUE) {
super.parallelRequest(1);
} else {
super.request(Math.max(elements, runningComposables));
}
}
}
public static final class Zippable {
final int index;
final O data;
public Zippable(int index, O data) {
this.index = index;
this.data = data;
}
}
}