rx.internal.operators.OperatorTimeoutBase Maven / Gradle / Ivy
/**
* 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 rx.*;
import rx.Observable.Operator;
import rx.functions.*;
import rx.internal.producers.ProducerArbiter;
import rx.observers.SerializedSubscriber;
import rx.subscriptions.SerialSubscription;
class OperatorTimeoutBase implements Operator {
final FirstTimeoutStub firstTimeoutStub;
final TimeoutStub timeoutStub;
final Observable extends T> other;
final Scheduler scheduler;
/**
* Set up the timeout action on the first value.
*
* @param
*/
/* package-private */interface FirstTimeoutStub extends
Func3, Long, Scheduler.Worker, Subscription> {
}
/**
* Set up the timeout action based on every value
*
* @param
*/
/* package-private */interface TimeoutStub extends
Func4, Long, T, Scheduler.Worker, Subscription> {
}
/* 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);
// 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);
final SerialSubscription serial = new SerialSubscription();
synchronizedSubscriber.add(serial);
TimeoutSubscriber timeoutSubscriber = new TimeoutSubscriber(synchronizedSubscriber, timeoutStub, serial, other, inner);
synchronizedSubscriber.add(timeoutSubscriber);
synchronizedSubscriber.setProducer(timeoutSubscriber.arbiter);
serial.set(firstTimeoutStub.call(timeoutSubscriber, 0L, inner));
return timeoutSubscriber;
}
/* package-private */static final class TimeoutSubscriber extends
Subscriber {
final SerialSubscription serial;
final SerializedSubscriber serializedSubscriber;
final TimeoutStub timeoutStub;
final Observable extends T> other;
final Scheduler.Worker inner;
final ProducerArbiter arbiter;
/** Guarded by this. */
boolean terminated;
/** Guarded by this. */
long actual;
TimeoutSubscriber(
SerializedSubscriber serializedSubscriber,
TimeoutStub timeoutStub, SerialSubscription serial,
Observable extends T> other,
Scheduler.Worker inner) {
this.serializedSubscriber = serializedSubscriber;
this.timeoutStub = timeoutStub;
this.serial = serial;
this.other = other;
this.inner = inner;
this.arbiter = new ProducerArbiter();
}
@Override
public void setProducer(Producer p) {
arbiter.setProducer(p);
}
@Override
public void onNext(T value) {
boolean onNextWins = false;
long a;
synchronized (this) {
if (!terminated) {
a = ++actual;
onNextWins = true;
} else {
a = actual;
}
}
if (onNextWins) {
serializedSubscriber.onNext(value);
serial.set(timeoutStub.call(this, a, value, inner));
}
}
@Override
public void onError(Throwable error) {
boolean onErrorWins = false;
synchronized (this) {
if (!terminated) {
terminated = true;
onErrorWins = true;
}
}
if (onErrorWins) {
serial.unsubscribe();
serializedSubscriber.onError(error);
}
}
@Override
public void onCompleted() {
boolean onCompletedWins = false;
synchronized (this) {
if (!terminated) {
terminated = true;
onCompletedWins = true;
}
}
if (onCompletedWins) {
serial.unsubscribe();
serializedSubscriber.onCompleted();
}
}
public void onTimeout(long seqId) {
long expected = seqId;
boolean timeoutWins = false;
synchronized (this) {
if (expected == actual && !terminated) {
terminated = true;
timeoutWins = true;
}
}
if (timeoutWins) {
if (other == null) {
serializedSubscriber.onError(new TimeoutException());
} else {
Subscriber second = new Subscriber() {
@Override
public void onNext(T t) {
serializedSubscriber.onNext(t);
}
@Override
public void onError(Throwable e) {
serializedSubscriber.onError(e);
}
@Override
public void onCompleted() {
serializedSubscriber.onCompleted();
}
@Override
public void setProducer(Producer p) {
arbiter.setProducer(p);
}
};
other.unsafeSubscribe(second);
serial.set(second);
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy