All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.reactivex.mantis.remote.observable.MergedObservable Maven / Gradle / Ivy

There is a newer version: 3.1.4
Show newest version
/*
 * Copyright 2019 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 io.reactivex.mantis.remote.observable;

import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.subjects.PublishSubject;
import rx.subjects.ReplaySubject;
import rx.subjects.Subject;


public class MergedObservable {

    private static final Logger logger = LoggerFactory.getLogger(MergedObservable.class);

    private Subject, Observable> subject;
    private MergeCounts counts;
    private Map> takeUntilSubjects =
            new HashMap>();

    private MergedObservable(int expectedTerminalCount, Subject, Observable> subject) {
        this.subject = subject;
        counts = new MergeCounts(expectedTerminalCount);
    }

    public static  MergedObservable create(int expectedTerminalCount) {
        return new MergedObservable(expectedTerminalCount, PublishSubject.>create());
    }

    public static  MergedObservable createWithReplay(int expectedTerminalCount) {
        return new MergedObservable(expectedTerminalCount, ReplaySubject.>create());
    }

    public synchronized void mergeIn(String key, Observable o) {
        if (!takeUntilSubjects.containsKey(key)) {
            PublishSubject takeUntil = PublishSubject.create();
            publishWithCallbacks(key, o.takeUntil(takeUntil), null, null);
            takeUntilSubjects.put(key, takeUntil);
        } else {
            logger.warn("Key alreay exists, ignoring merge request for observable with key: " + key);
        }
    }

    public synchronized void mergeIn(String key, Observable o, Action1 errorCallback,
                                     Action0 successCallback) {
        if (!takeUntilSubjects.containsKey(key)) {
            PublishSubject takeUntil = PublishSubject.create();
            publishWithCallbacks(key, o.takeUntil(takeUntil), errorCallback, successCallback);
            takeUntilSubjects.put(key, takeUntil);
        } else {
            logger.warn("Key alreay exists, ignoring merge request for observable with key: " + key);
        }
    }

    synchronized void clear() {
        takeUntilSubjects.clear();
    }

    private synchronized void publishWithCallbacks(final String key, Observable o,
                                                   final Action1 errorCallback, final Action0 successCallback) {
        subject.onNext(o
                .doOnError(new Action1() {
                    @Override
                    public void call(Throwable t1) {
                        if (errorCallback != null) {
                            errorCallback.call(t1);
                        }
                        logger.error("Inner observable with key: " + key + " terminated with onError, calling onError() on outer observable." + t1.getMessage(), t1);
                        takeUntilSubjects.remove(key);
                        subject.onError(t1);
                    }
                })
                .doOnCompleted(new Action0() {
                    @Override
                    public void call() {
                        if (successCallback != null) {
                            successCallback.call();
                        }
                        logger.debug("Inner observable with key: " + key + " completed, incrementing terminal count.");
                        takeUntilSubjects.remove(key);
                        if (counts.incrementTerminalCountAndCheck()) {
                            logger.debug("All inner observables terminated, calling onCompleted() on outer observable.");
                            subject.onCompleted();
                        }
                    }
                }));
    }

    public synchronized void forceComplete(String key) {
        PublishSubject takeUntil = takeUntilSubjects.get(key);
        if (takeUntil != null) {
            takeUntil.onNext(1); // complete observable
        } else {
            logger.debug("Nothing to force complete, key doesn't exist: " + key);
        }
    }

    public synchronized Observable> get() {
        return subject;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy