/** * 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.observables; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; import rx.Observable; import rx.Subscriber; import rx.functions.Action1; import rx.functions.Func1; import rx.functions.Functions; import rx.internal.operators.BlockingOperatorLatest; import rx.internal.operators.BlockingOperatorMostRecent; import rx.internal.operators.BlockingOperatorNext; import rx.internal.operators.BlockingOperatorToFuture; import rx.internal.operators.BlockingOperatorToIterator; /** * An extension of {@link Observable} that provides blocking operators. * <p> * You construct a {@code BlockingObservable} from an {@code Observable} with {@link #from(Observable)} or * {@link Observable#toBlocking()}. * <p> * The documentation for this interface makes use of a form of marble diagram that has been modified to * illustrate blocking operators. The following legend explains these marble diagrams: * <p> * <img width="640" height="301" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.legend.png" alt=""> * <p> * For more information see the * <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators">Blocking * Observable Operators</a> page at the RxJava Wiki. * * @param <T> * the type of item emitted by the {@code BlockingObservable} */ public class BlockingObservable<T> { private final Observable<? extends T> o; private BlockingObservable(Observable<? extends T> o) { this.o = o; } /** * Converts an {@link Observable} into a {@code BlockingObservable}. * * @param o * the {@link Observable} you want to convert * @return a {@code BlockingObservable} version of {@code o} */ public static <T> BlockingObservable<T> from(final Observable<? extends T> o) { return new BlockingObservable<T>(o); } /** * Invokes a method on each item emitted by this {@code BlockingObservable} and blocks until the Observable * completes. * <p> * <em>Note:</em> This will block even if the underlying Observable is asynchronous. * <p> * This is similar to {@link Observable#subscribe(Subscriber)}, but it blocks. Because it blocks it does not * need the {@link Subscriber#onCompleted()} or {@link Subscriber#onError(Throwable)} methods. * <p> * <img width="640" height="330" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.forEach.png" alt=""> * * @param onNext * the {@link Action1} to invoke for each item emitted by the {@code BlockingObservable} * @throws RuntimeException * if an error occurs * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#foreach">RxJava Wiki: forEach()</a> */ public void forEach(final Action1<? super T> onNext) { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<Throwable> exceptionFromOnError = new AtomicReference<Throwable>(); /* * Use 'subscribe' instead of 'unsafeSubscribe' for Rx contract behavior * as this is the final subscribe in the chain. */ o.subscribe(new Subscriber<T>() { @Override public void onCompleted() { latch.countDown(); } @Override public void onError(Throwable e) { /* * If we receive an onError event we set the reference on the * outer thread so we can git it and throw after the * latch.await(). * * We do this instead of throwing directly since this may be on * a different thread and the latch is still waiting. */ exceptionFromOnError.set(e); latch.countDown(); } @Override public void onNext(T args) { onNext.call(args); } }); // block until the subscription completes and then return try { latch.await(); } catch (InterruptedException e) { // set the interrupted flag again so callers can still get it // for more information see https://github.com/Netflix/RxJava/pull/147#issuecomment-13624780 Thread.currentThread().interrupt(); // using Runtime so it is not checked throw new RuntimeException("Interrupted while waiting for subscription to complete.", e); } if (exceptionFromOnError.get() != null) { if (exceptionFromOnError.get() instanceof RuntimeException) { throw (RuntimeException) exceptionFromOnError.get(); } else { throw new RuntimeException(exceptionFromOnError.get()); } } } /** * Returns an {@link Iterator} that iterates over all items emitted by this {@code BlockingObservable}. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.getIterator.png" alt=""> * * @return an {@link Iterator} that can iterate over the items emitted by this {@code BlockingObservable} * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#transformations-tofuture-toiterable-and-toiteratorgetiterator">RxJava Wiki: getIterator()</a> */ public Iterator<T> getIterator() { return BlockingOperatorToIterator.toIterator(o); } /** * Returns the first item emitted by this {@code BlockingObservable}, or throws * {@code NoSuchElementException} if it emits no items. * * @return the first item emitted by this {@code BlockingObservable} * @throws NoSuchElementException * if this {@code BlockingObservable} emits no items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#first-and-firstordefault">RxJava Wiki: first()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/hh229177.aspx">MSDN: Observable.First</a> */ public T first() { return from(o.first()).single(); } /** * Returns the first item emitted by this {@code BlockingObservable} that matches a predicate, or throws * {@code NoSuchElementException} if it emits no such item. * * @param predicate * a predicate function to evaluate items emitted by this {@code BlockingObservable} * @return the first item emitted by this {@code BlockingObservable} that matches the predicate * @throws NoSuchElementException * if this {@code BlockingObservable} emits no such items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#first-and-firstordefault">RxJava Wiki: first()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/hh229739.aspx">MSDN: Observable.First</a> */ public T first(Func1<? super T, Boolean> predicate) { return from(o.first(predicate)).single(); } /** * Returns the first item emitted by this {@code BlockingObservable}, or a default value if it emits no * items. * * @param defaultValue * a default value to return if this {@code BlockingObservable} emits no items * @return the first item emitted by this {@code BlockingObservable}, or the default value if it emits no * items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#first-and-firstordefault">RxJava Wiki: firstOrDefault()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/hh229320.aspx">MSDN: Observable.FirstOrDefault</a> */ public T firstOrDefault(T defaultValue) { return from(o.take(1)).singleOrDefault(defaultValue); } /** * Returns the first item emitted by this {@code BlockingObservable} that matches a predicate, or a default * value if it emits no such items. * * @param defaultValue * a default value to return if this {@code BlockingObservable} emits no matching items * @param predicate * a predicate function to evaluate items emitted by this {@code BlockingObservable} * @return the first item emitted by this {@code BlockingObservable} that matches the predicate, or the * default value if this {@code BlockingObservable} emits no matching items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#first-and-firstordefault">RxJava Wiki: firstOrDefault()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/hh229759.aspx">MSDN: Observable.FirstOrDefault</a> */ public T firstOrDefault(T defaultValue, Func1<? super T, Boolean> predicate) { return from(o.filter(predicate)).firstOrDefault(defaultValue); } /** * Returns the last item emitted by this {@code BlockingObservable}, or throws * {@code NoSuchElementException} if this {@code BlockingObservable} emits no items. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.last.png" alt=""> * * @return the last item emitted by this {@code BlockingObservable} * @throws NoSuchElementException * if this {@code BlockingObservable} emits no items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#last-and-lastordefault">RxJava Wiki: last()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.last.aspx">MSDN: Observable.Last</a> */ public T last() { return from(o.last()).single(); } /** * Returns the last item emitted by this {@code BlockingObservable} that matches a predicate, or throws * {@code NoSuchElementException} if it emits no such items. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.last.p.png" alt=""> * * @param predicate * a predicate function to evaluate items emitted by the {@code BlockingObservable} * @return the last item emitted by the {@code BlockingObservable} that matches the predicate * @throws NoSuchElementException * if this {@code BlockingObservable} emits no items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#last-and-lastordefault">RxJava Wiki: last()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.last.aspx">MSDN: Observable.Last</a> */ public T last(final Func1<? super T, Boolean> predicate) { return from(o.last(predicate)).single(); } /** * Returns the last item emitted by this {@code BlockingObservable}, or a default value if it emits no * items. * <p> * <img width="640" height="310" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.lastOrDefault.png" alt=""> * * @param defaultValue * a default value to return if this {@code BlockingObservable} emits no items * @return the last item emitted by the {@code BlockingObservable}, or the default value if it emits no * items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#last-and-lastordefault">RxJava Wiki: lastOrDefault()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.lastordefault.aspx">MSDN: Observable.LastOrDefault</a> */ public T lastOrDefault(T defaultValue) { return from(o.takeLast(1)).singleOrDefault(defaultValue); } /** * Returns the last item emitted by this {@code BlockingObservable} that matches a predicate, or a default * value if it emits no such items. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.lastOrDefault.p.png" alt=""> * * @param defaultValue * a default value to return if this {@code BlockingObservable} emits no matching items * @param predicate * a predicate function to evaluate items emitted by this {@code BlockingObservable} * @return the last item emitted by this {@code BlockingObservable} that matches the predicate, or the * default value if it emits no matching items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#last-and-lastordefault">RxJava Wiki: lastOrDefault()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.lastordefault.aspx">MSDN: Observable.LastOrDefault</a> */ public T lastOrDefault(T defaultValue, Func1<? super T, Boolean> predicate) { return from(o.filter(predicate)).lastOrDefault(defaultValue); } /** * Returns an {@link Iterable} that always returns the item most recently emitted by this * {@code BlockingObservable}. * <p> * <img width="640" height="490" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.mostRecent.png" alt=""> * * @param initialValue * the initial value that the {@link Iterable} sequence will yield if this * {@code BlockingObservable} has not yet emitted an item * @return an {@link Iterable} that on each iteration returns the item that this {@code BlockingObservable} * has most recently emitted * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#mostrecent">RxJava wiki: mostRecent()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/hh229751.aspx">MSDN: Observable.MostRecent</a> */ public Iterable<T> mostRecent(T initialValue) { return BlockingOperatorMostRecent.mostRecent(o, initialValue); } /** * Returns an {@link Iterable} that blocks until this {@code BlockingObservable} emits another item, then * returns that item. * <p> * <img width="640" height="490" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.next.png" alt=""> * * @return an {@link Iterable} that blocks upon each iteration until this {@code BlockingObservable} emits * a new item, whereupon the Iterable returns that item * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#next">RxJava Wiki: next()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/hh211897.aspx">MSDN: Observable.Next</a> */ public Iterable<T> next() { return BlockingOperatorNext.next(o); } /** * Returns an {@link Iterable} that returns the latest item emitted by this {@code BlockingObservable}, * waiting if necessary for one to become available. * <p> * If this {@code BlockingObservable} produces items faster than {@code Iterator.next} takes them, * {@code onNext} events might be skipped, but {@code onError} or {@code onCompleted} events are not. * <p> * Note also that an {@code onNext} directly followed by {@code onCompleted} might hide the {@code onNext} * event. * * @return an Iterable that always returns the latest item emitted by this {@code BlockingObservable} * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#latest">RxJava wiki: latest()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/hh212115.aspx">MSDN: Observable.Latest</a> */ public Iterable<T> latest() { return BlockingOperatorLatest.latest(o); } /** * If this {@code BlockingObservable} completes after emitting a single item, return that item, otherwise * throw a {@code NoSuchElementException}. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.single.png" alt=""> * * @return the single item emitted by this {@code BlockingObservable} * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#single-and-singleordefault">RxJava Wiki: single()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.single.aspx">MSDN: Observable.Single</a> */ public T single() { return from(o.single()).toIterable().iterator().next(); } /** * If this {@code BlockingObservable} completes after emitting a single item that matches a given predicate, * return that item, otherwise throw a {@code NoSuchElementException}. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.single.p.png" alt=""> * * @param predicate * a predicate function to evaluate items emitted by this {@link BlockingObservable} * @return the single item emitted by this {@code BlockingObservable} that matches the predicate * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#single-and-singleordefault">RxJava Wiki: single()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.single.aspx">MSDN: Observable.Single</a> */ public T single(Func1<? super T, Boolean> predicate) { return from(o.single(predicate)).toIterable().iterator().next(); } /** * If this {@code BlockingObservable} completes after emitting a single item, return that item; if it emits * more than one item, throw an {@code IllegalArgumentException}; if it emits no items, return a default * value. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.singleOrDefault.png" alt=""> * * @param defaultValue * a default value to return if this {@code BlockingObservable} emits no items * @return the single item emitted by this {@code BlockingObservable}, or the default value if it emits no * items * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#single-and-singleordefault">RxJava Wiki: singleOrDefault()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.singleordefault.aspx">MSDN: Observable.SingleOrDefault</a> */ public T singleOrDefault(T defaultValue) { return from(o.map(Functions.<T>identity()).singleOrDefault(defaultValue)).single(); } /** * If this {@code BlockingObservable} completes after emitting a single item that matches a predicate, * return that item; if it emits more than one such item, throw an {@code IllegalArgumentException}; if it * emits no items, return a default value. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.singleOrDefault.p.png" alt=""> * * @param defaultValue * a default value to return if this {@code BlockingObservable} emits no matching items * @param predicate * a predicate function to evaluate items emitted by this {@code BlockingObservable} * @return the single item emitted by the {@code BlockingObservable} that matches the predicate, or the * default value if no such items are emitted * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#single-and-singleordefault">RxJava Wiki: singleOrDefault()</a> * @see <a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.singleordefault.aspx">MSDN: Observable.SingleOrDefault</a> */ public T singleOrDefault(T defaultValue, Func1<? super T, Boolean> predicate) { return from(o.filter(predicate)).singleOrDefault(defaultValue); } /** * Returns a {@link Future} representing the single value emitted by this {@code BlockingObservable}. * <p> * If {@link BlockingObservable} emits more than one item, {@link java.util.concurrent.Future} will receive an * {@link java.lang.IllegalArgumentException}. If {@link BlockingObservable} is empty, {@link java.util.concurrent.Future} * will receive an {@link java.util.NoSuchElementException}. * <p> * If the {@code BlockingObservable} may emit more than one item, use {@code Observable.toList().toBlocking().toFuture()}. * <p> * <img width="640" height="395" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.toFuture.png" alt=""> * * @return a {@link Future} that expects a single item to be emitted by this {@code BlockingObservable} * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#transformations-tofuture-toiterable-and-toiteratorgetiterator">RxJava Wiki: toFuture()</a> */ public Future<T> toFuture() { return BlockingOperatorToFuture.toFuture(o); } /** * Converts this {@code BlockingObservable} into an {@link Iterable}. * <p> * <img width="640" height="315" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.toIterable.png" alt=""> * * @return an {@link Iterable} version of this {@code BlockingObservable} * @see <a href="https://github.com/Netflix/RxJava/wiki/Blocking-Observable-Operators#transformations-tofuture-toiterable-and-toiteratorgetiterator">RxJava Wiki: toIterable()</a> */ public Iterable<T> toIterable() { return new Iterable<T>() { @Override public Iterator<T> iterator() { return getIterator(); } }; } }