/* * Copyright 2015 Jacek Marchwicki <jacek.marchwicki@gmail.com> * * 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 com.appunite.rx.operators; import java.util.concurrent.locks.ReentrantLock; import rx.Observable; import rx.Observer; import rx.Subscriber; import rx.exceptions.OnErrorThrowable; import rx.functions.Func1; import rx.functions.Func2; public class OperatorMergeNextToken<T, K> implements Observable.Operator<T, K> { private final T initialValue; private final Func2<T, K, Observable<T>> merge; private OperatorMergeNextToken(final T initialValue, final Func2<T, K, Observable<T>> merge) { this.initialValue = initialValue; this.merge = merge; } public static <T, K> OperatorMergeNextToken<T, K> create(final T initialValue, final Func2<T, K, Observable<T>> merge) { return new OperatorMergeNextToken<>(initialValue, merge); } public static <T, K> OperatorMergeNextToken<T, K> create(final Func2<T, K, Observable<T>> merge) { return new OperatorMergeNextToken<>(null, merge); } public static <T> OperatorMergeNextToken<T, Object> create(final Func1<T, Observable<T>> merge) { return new OperatorMergeNextToken<>(null, new IgnoreSourceParameter<>(merge)); } public static <T> OperatorMergeNextToken<T, Object> create(T initialValue, final Func1<T, Observable<T>> merge) { return new OperatorMergeNextToken<>(initialValue, new IgnoreSourceParameter<>(merge)); } @Override public Subscriber<? super K> call(final Subscriber<? super T> child) { return new Subscriber<K>(child) { private final ReentrantLock lock = new ReentrantLock(); private T previous = initialValue; private boolean skip = false; @Override public void onCompleted() { child.onCompleted(); } @Override public void onError(final Throwable e) { child.onError(e); } @Override public void onNext(final K k) { final Observer<T> observer = new Observer<T>() { @Override public void onCompleted() { lock.lock(); try { skip = false; } finally { lock.unlock(); } } @Override public void onError(final Throwable e) { child.onError(e); } @Override public void onNext(final T t) { lock.lock(); try { previous = t; child.onNext(t); } finally { lock.unlock(); } } }; lock.lock(); try { if (skip) { request(1); return; } skip = true; } finally { lock.unlock(); } try { final Observable<T> nextObservable = merge.call(previous, k); child.add(nextObservable.subscribe(observer)); } catch (Throwable e) { child.onError(OnErrorThrowable.addValueAsLastCause(e, k)); } } }; } private static class IgnoreSourceParameter<T> implements Func2<T, Object, Observable<T>> { private final Func1<T, Observable<T>> merge; public IgnoreSourceParameter(final Func1<T, Observable<T>> merge) { this.merge = merge; } @Override public Observable<T> call(final T t, final Object object) { return merge.call(t); } } }