rx.internal.operators.OperatorMerge Maven / Gradle / Ivy
Show all versions of rxjava-core Show documentation
/**
* Copyright 2014 Netflix, 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 rx.internal.operators;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import rx.Observable;
import rx.Observable.Operator;
import rx.Subscriber;
import rx.exceptions.Exceptions;
import rx.observers.SerializedSubscriber;
import rx.subscriptions.CompositeSubscription;
/**
* Flattens a list of {@link Observable}s into one {@code Observable}, without any transformation.
*
*
*
* You can combine the items emitted by multiple {@code Observable}s so that they act like a single
* {@code Observable}, by using the merge operation.
*
* @param the type of the items emitted by both the source and merged {@code Observable}s
*/
public final class OperatorMerge implements Operator> {
@Override
public Subscriber> call(final Subscriber super T> outerOperation) {
final Subscriber o = new SerializedSubscriber(outerOperation);
final CompositeSubscription childrenSubscriptions = new CompositeSubscription();
outerOperation.add(childrenSubscriptions);
return new MergeSubscriber(o, childrenSubscriptions);
}
static final class MergeSubscriber extends Subscriber> {
final Subscriber actual;
final CompositeSubscription childrenSubscriptions;
volatile int wip;
volatile boolean completed;
@SuppressWarnings("rawtypes")
static final AtomicIntegerFieldUpdater WIP_UPDATER
= AtomicIntegerFieldUpdater.newUpdater(MergeSubscriber.class, "wip");
public MergeSubscriber(Subscriber actual, CompositeSubscription childrenSubscriptions) {
super(actual);
this.actual = actual;
this.childrenSubscriptions = childrenSubscriptions;
}
@Override
public void onNext(Observable extends T> t) {
WIP_UPDATER.incrementAndGet(this);
Subscriber i = new InnerSubscriber(this);
childrenSubscriptions.add(i);
t.unsafeSubscribe(i);
}
@Override
public void onError(Throwable e) {
actual.onError(e);
unsubscribe();
}
@Override
public void onCompleted() {
completed = true;
if (wip == 0) {
actual.onCompleted();
}
}
void completeInner(InnerSubscriber s) {
try {
if (WIP_UPDATER.decrementAndGet(this) == 0 && completed) {
actual.onCompleted();
}
} finally {
childrenSubscriptions.remove(s);
}
}
}
static final class InnerSubscriber extends Subscriber {
final Subscriber super T> actual;
final MergeSubscriber parent;
/** Make sure the inner termination events are delivered only once. */
volatile int once;
@SuppressWarnings("rawtypes")
static final AtomicIntegerFieldUpdater ONCE_UPDATER
= AtomicIntegerFieldUpdater.newUpdater(InnerSubscriber.class, "once");
public InnerSubscriber(MergeSubscriber parent) {
this.parent = parent;
this.actual = parent.actual;
}
@Override
public void onNext(T t) {
actual.onNext(t);
}
@Override
public void onError(Throwable e) {
Exceptions.throwIfFatal(e);
if (ONCE_UPDATER.compareAndSet(this, 0, 1)) {
parent.onError(e);
}
}
@Override
public void onCompleted() {
if (ONCE_UPDATER.compareAndSet(this, 0, 1)) {
parent.completeInner(this);
}
}
}
}