rx.internal.operators.OperatorTimeoutBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rxjava-core Show documentation
Show all versions of rxjava-core Show documentation
rxjava-core developed by Netflix
The newest version!
/**
* 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.TimeoutException;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import rx.Observable;
import rx.Observable.Operator;
import rx.Scheduler;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Func3;
import rx.functions.Func4;
import rx.observers.SerializedSubscriber;
import rx.subscriptions.SerialSubscription;
class OperatorTimeoutBase implements Operator {
/**
* Set up the timeout action on the first value.
*
* @param
*/
/* package-private */static interface FirstTimeoutStub extends
Func3, Long, Scheduler.Worker, Subscription> {
}
/**
* Set up the timeout action based on every value
*
* @param
*/
/* package-private */static interface TimeoutStub extends
Func4, Long, T, Scheduler.Worker, Subscription> {
}
private final FirstTimeoutStub firstTimeoutStub;
private final TimeoutStub timeoutStub;
private final Observable extends T> other;
private final Scheduler scheduler;
/* package-private */OperatorTimeoutBase(FirstTimeoutStub firstTimeoutStub, TimeoutStub timeoutStub, Observable extends T> other, Scheduler scheduler) {
this.firstTimeoutStub = firstTimeoutStub;
this.timeoutStub = timeoutStub;
this.other = other;
this.scheduler = scheduler;
}
@Override
public Subscriber super T> call(Subscriber super T> subscriber) {
Scheduler.Worker inner = scheduler.createWorker();
subscriber.add(inner);
final SerialSubscription serial = new SerialSubscription();
subscriber.add(serial);
// Use SynchronizedSubscriber for safe memory access
// as the subscriber will be accessed in the current thread or the
// scheduler or other Observables.
final SerializedSubscriber synchronizedSubscriber = new SerializedSubscriber(subscriber);
TimeoutSubscriber timeoutSubscriber = new TimeoutSubscriber(synchronizedSubscriber, timeoutStub, serial, other, inner);
serial.set(firstTimeoutStub.call(timeoutSubscriber, 0L, inner));
return timeoutSubscriber;
}
/* package-private */static class TimeoutSubscriber extends
Subscriber {
private final SerialSubscription serial;
private final Object gate = new Object();
private final SerializedSubscriber serializedSubscriber;
private final TimeoutStub timeoutStub;
private final Observable extends T> other;
private final Scheduler.Worker inner;
volatile int terminated;
volatile long actual;
@SuppressWarnings("rawtypes")
static final AtomicIntegerFieldUpdater TERMINATED_UPDATER
= AtomicIntegerFieldUpdater.newUpdater(TimeoutSubscriber.class, "terminated");
@SuppressWarnings("rawtypes")
static final AtomicLongFieldUpdater ACTUAL_UPDATER
= AtomicLongFieldUpdater.newUpdater(TimeoutSubscriber.class, "actual");
private TimeoutSubscriber(
SerializedSubscriber serializedSubscriber,
TimeoutStub timeoutStub, SerialSubscription serial,
Observable extends T> other,
Scheduler.Worker inner) {
super(serializedSubscriber);
this.serializedSubscriber = serializedSubscriber;
this.timeoutStub = timeoutStub;
this.serial = serial;
this.other = other;
this.inner = inner;
}
@Override
public void onNext(T value) {
boolean onNextWins = false;
synchronized (gate) {
if (terminated == 0) {
ACTUAL_UPDATER.incrementAndGet(this);
onNextWins = true;
}
}
if (onNextWins) {
serializedSubscriber.onNext(value);
serial.set(timeoutStub.call(this, actual, value, inner));
}
}
@Override
public void onError(Throwable error) {
boolean onErrorWins = false;
synchronized (gate) {
if (TERMINATED_UPDATER.getAndSet(this, 1) == 0) {
onErrorWins = true;
}
}
if (onErrorWins) {
serial.unsubscribe();
serializedSubscriber.onError(error);
}
}
@Override
public void onCompleted() {
boolean onCompletedWins = false;
synchronized (gate) {
if (TERMINATED_UPDATER.getAndSet(this, 1) == 0) {
onCompletedWins = true;
}
}
if (onCompletedWins) {
serial.unsubscribe();
serializedSubscriber.onCompleted();
}
}
public void onTimeout(long seqId) {
long expected = seqId;
boolean timeoutWins = false;
synchronized (gate) {
if (expected == actual && TERMINATED_UPDATER.getAndSet(this, 1) == 0) {
timeoutWins = true;
}
}
if (timeoutWins) {
if (other == null) {
serializedSubscriber.onError(new TimeoutException());
} else {
other.unsafeSubscribe(serializedSubscriber);
serial.set(serializedSubscriber);
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy