/** * Copyright (c) 2016-present, RxJava Contributors. * * 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.internal.operators.completable; import java.util.Iterator; import java.util.concurrent.atomic.*; import io.reactivex.*; import io.reactivex.disposables.*; import io.reactivex.exceptions.Exceptions; import io.reactivex.internal.functions.ObjectHelper; import io.reactivex.plugins.RxJavaPlugins; public final class CompletableMergeIterable extends Completable { final Iterable<? extends CompletableSource> sources; public CompletableMergeIterable(Iterable<? extends CompletableSource> sources) { this.sources = sources; } @Override public void subscribeActual(final CompletableObserver s) { final CompositeDisposable set = new CompositeDisposable(); s.onSubscribe(set); Iterator<? extends CompletableSource> iterator; try { iterator = ObjectHelper.requireNonNull(sources.iterator(), "The source iterator returned is null"); } catch (Throwable e) { Exceptions.throwIfFatal(e); s.onError(e); return; } final AtomicInteger wip = new AtomicInteger(1); MergeCompletableObserver shared = new MergeCompletableObserver(s, set, wip); for (;;) { if (set.isDisposed()) { return; } boolean b; try { b = iterator.hasNext(); } catch (Throwable e) { Exceptions.throwIfFatal(e); set.dispose(); shared.onError(e); return; } if (!b) { break; } if (set.isDisposed()) { return; } CompletableSource c; try { c = ObjectHelper.requireNonNull(iterator.next(), "The iterator returned a null CompletableSource"); } catch (Throwable e) { Exceptions.throwIfFatal(e); set.dispose(); shared.onError(e); return; } if (set.isDisposed()) { return; } wip.getAndIncrement(); c.subscribe(shared); } shared.onComplete(); } static final class MergeCompletableObserver extends AtomicBoolean implements CompletableObserver { private static final long serialVersionUID = -7730517613164279224L; final CompositeDisposable set; final CompletableObserver actual; final AtomicInteger wip; MergeCompletableObserver(CompletableObserver actual, CompositeDisposable set, AtomicInteger wip) { this.actual = actual; this.set = set; this.wip = wip; } @Override public void onSubscribe(Disposable d) { set.add(d); } @Override public void onError(Throwable e) { set.dispose(); if (compareAndSet(false, true)) { actual.onError(e); } else { RxJavaPlugins.onError(e); } } @Override public void onComplete() { if (wip.decrementAndGet() == 0) { if (compareAndSet(false, true)) { actual.onComplete(); } } } } }