com.netflix.eureka2.interests.NotificationsSubject Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eureka-core Show documentation
Show all versions of eureka-core Show documentation
eureka-core developed by Netflix
The newest version!
package com.netflix.eureka2.interests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Subscriber;
import rx.observers.SafeSubscriber;
import rx.subjects.PublishSubject;
import rx.subjects.Subject;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A special {@link Subject} implementation for {@link ChangeNotification}s. This has the capability to optionally
* start/stop caching on demand, i.e. publish of data to the subscribers will be paused after calling the method
* {@link #pause()} and the same can be resumed after calling the method {@link #resume()}
*
* @author Nitesh Kant
*/
public class NotificationsSubject extends Subject, ChangeNotification>{
public enum ResumeResult {NotPaused, DuplicateResume, Resumed}
private enum ResumeState {NotPaused, Resuming, Error}
private static final Logger logger = LoggerFactory.getLogger(NotificationsSubject.class);
private final AtomicInteger resumeState = new AtomicInteger(ResumeState.NotPaused.ordinal());
private AtomicBoolean paused;
private final PublishSubject> notificationSubject;
private final NotificationsSubjectSubscriber subscriber;
private final ConcurrentLinkedQueue> notificationsWhenPaused; // TODO: See if this should be bounded.
private volatile boolean completedWhenPaused;
private volatile Throwable errorWhenPaused;
protected NotificationsSubject(OnSubscribe> onSubscribe,
PublishSubject> notificationSubject) {
super(onSubscribe);
subscriber = new NotificationsSubjectSubscriber();
this.notificationSubject = notificationSubject;
notificationsWhenPaused = new ConcurrentLinkedQueue>();
paused = new AtomicBoolean();
}
public static NotificationsSubject create() {
final PublishSubject> notificationSubject = PublishSubject.create();
return new NotificationsSubject(new OnSubscribe>() {
@Override
public void call(Subscriber super ChangeNotification> subscriber) {
notificationSubject.subscribe(subscriber);
}
}, notificationSubject);
}
public boolean isPaused() {
return paused.get();
}
public void pause() {
paused.set(true);
}
@Override
public boolean hasObservers() {
return notificationSubject.hasObservers();
}
public ResumeResult resume() {
if (isPaused()) {
if (resumeState.compareAndSet(ResumeState.NotPaused.ordinal(), ResumeState.Resuming.ordinal())) {
try {
ChangeNotification nextPolled;
while ((nextPolled = notificationsWhenPaused.poll()) != null) { // drain pending queue.
notificationSubject.onNext(nextPolled); // Since pause flag is not yet unset, don't call this.onNext()
}
paused.set(false);
if (completedWhenPaused) {
onCompleted();
} else if (null != errorWhenPaused) {
onError(errorWhenPaused);
}
return ResumeResult.Resumed;
} catch (Exception e) {
logger.error("Error while resuming notifications subject.", e);
resumeState.compareAndSet(ResumeState.Resuming.ordinal(), ResumeState.Error.ordinal());
onError(e);
return ResumeResult.Resumed;
} finally {
resumeState.compareAndSet(ResumeState.Resuming.ordinal(), ResumeState.NotPaused.ordinal());
}
} else {
return ResumeResult.DuplicateResume;
}
} else {
return ResumeResult.NotPaused;
}
}
@Override
public void onCompleted() {
subscriber.onCompleted();
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
@Override
public void onNext(ChangeNotification notification) {
subscriber.onNext(notification);
}
/**
* This makes sure that the {@link NotificationsSubject} follows Rx contracts i.e.
* it does not honor onNext() after termination and onNext() error causes onError().
*/
private class NotificationsSubjectSubscriber extends SafeSubscriber> {
public NotificationsSubjectSubscriber() {
super(new Subscriber>() {
@Override
public void onCompleted() {
if (paused.get()) {
completedWhenPaused = true;
} else {
notificationSubject.onCompleted();
}
}
@Override
public void onError(Throwable e) {
if (paused.get()) {
errorWhenPaused = e;
} else {
notificationSubject.onError(e);
}
}
@Override
public void onNext(ChangeNotification notification) {
if (paused.get()) {
notificationsWhenPaused.add(notification);
} else {
notificationSubject.onNext(notification);
}
}
});
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy