|
27 | 27 | import java.util.concurrent.CountDownLatch;
|
28 | 28 | import java.util.concurrent.Future;
|
29 | 29 | import java.util.concurrent.TimeUnit;
|
30 |
| -import java.util.concurrent.TimeoutException; |
31 | 30 | import java.util.concurrent.atomic.AtomicReference;
|
32 | 31 |
|
33 | 32 | import org.junit.Before;
|
@@ -156,11 +155,30 @@ public Subscription subscribe(Observer<T> observer) {
|
156 | 155 | throw new IllegalStateException("onSubscribe function can not be null.");
|
157 | 156 | // the subscribe function can also be overridden but generally that's not the appropriate approach so I won't mention that in the exception
|
158 | 157 | }
|
159 |
| - if (isTrusted) { |
160 |
| - return onSubscribe.call(observer); |
161 |
| - } else { |
162 |
| - AtomicObservableSubscription subscription = new AtomicObservableSubscription(); |
163 |
| - return subscription.wrap(onSubscribe.call(new AtomicObserver<T>(subscription, observer))); |
| 158 | + try { |
| 159 | + if (isTrusted) { |
| 160 | + Subscription s = onSubscribe.call(observer); |
| 161 | + if (s == null) { |
| 162 | + // this generally shouldn't be the case on a 'trusted' onSubscribe but in case it happens |
| 163 | + // we want to gracefully handle it the same as AtomicObservableSubscription does |
| 164 | + return Subscriptions.empty(); |
| 165 | + } else { |
| 166 | + return s; |
| 167 | + } |
| 168 | + } else { |
| 169 | + AtomicObservableSubscription subscription = new AtomicObservableSubscription(); |
| 170 | + return subscription.wrap(onSubscribe.call(new AtomicObserver<T>(subscription, observer))); |
| 171 | + } |
| 172 | + } catch (Exception e) { |
| 173 | + // if an unhandled error occurs executing the onSubscribe we will propagate it |
| 174 | + try { |
| 175 | + observer.onError(e); |
| 176 | + } catch (Exception e2) { |
| 177 | + // if this happens it means the onError itself failed (perhaps an invalid function implementation) |
| 178 | + // so we are unable to propagate the error correctly and will just throw |
| 179 | + throw new RuntimeException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2); |
| 180 | + } |
| 181 | + return Subscriptions.empty(); |
164 | 182 | }
|
165 | 183 | }
|
166 | 184 |
|
@@ -415,6 +433,18 @@ public void onNext(T args) {
|
415 | 433 | }
|
416 | 434 | }
|
417 | 435 |
|
| 436 | + /** |
| 437 | + * Invokes an action for each element in the observable sequence, and blocks until the sequence is terminated. |
| 438 | + * <p> |
| 439 | + * NOTE: This will block even if the Observable is asynchronous. |
| 440 | + * <p> |
| 441 | + * This is similar to {@link #subscribe(Observer)} but blocks. Because it blocks it does not need the {@link Observer#onCompleted()} or {@link Observer#onError(Exception)} methods. |
| 442 | + * |
| 443 | + * @param onNext |
| 444 | + * {@link Action1} |
| 445 | + * @throws RuntimeException |
| 446 | + * if error occurs |
| 447 | + */ |
418 | 448 | @SuppressWarnings({ "rawtypes", "unchecked" })
|
419 | 449 | public void forEach(final Object o) {
|
420 | 450 | if (o instanceof Action1) {
|
@@ -3405,6 +3435,25 @@ public Boolean call(String s) {
|
3405 | 3435 | }));
|
3406 | 3436 | }
|
3407 | 3437 |
|
| 3438 | + @Test |
| 3439 | + public void testOnSubscribeFails() { |
| 3440 | + @SuppressWarnings("unchecked") |
| 3441 | + Observer<String> observer = mock(Observer.class); |
| 3442 | + final RuntimeException re = new RuntimeException("bad impl"); |
| 3443 | + Observable<String> o = Observable.create(new Func1<Observer<String>, Subscription>() { |
| 3444 | + |
| 3445 | + @Override |
| 3446 | + public Subscription call(Observer<String> t1) { |
| 3447 | + throw re; |
| 3448 | + } |
| 3449 | + |
| 3450 | + }); |
| 3451 | + o.subscribe(observer); |
| 3452 | + verify(observer, times(0)).onNext(anyString()); |
| 3453 | + verify(observer, times(0)).onCompleted(); |
| 3454 | + verify(observer, times(1)).onError(re); |
| 3455 | + } |
| 3456 | + |
3408 | 3457 | @Test
|
3409 | 3458 | public void testLastEmptyObservable() {
|
3410 | 3459 | Observable<String> obs = Observable.toObservable();
|
|
0 commit comments