1515 */
1616package rx .internal .operators ;
1717
18+ import java .util .Queue ;
19+ import java .util .concurrent .ConcurrentLinkedQueue ;
1820import java .util .concurrent .atomic .AtomicIntegerFieldUpdater ;
1921import java .util .concurrent .atomic .AtomicLongFieldUpdater ;
2022
2123import rx .Observable ;
2224import rx .Observable .Operator ;
2325import rx .Producer ;
2426import rx .Subscriber ;
27+ import rx .exceptions .CompositeException ;
2528import rx .exceptions .MissingBackpressureException ;
29+ import rx .exceptions .OnErrorThrowable ;
2630import rx .functions .Func1 ;
2731import rx .internal .util .RxRingBuffer ;
2832import rx .internal .util .ScalarSynchronousObservable ;
3337 * <p>
3438 * <img width="640" height="380" src="https://raw.githubusercontent.com/wiki/Netflix/RxJava/images/rx-operators/merge.png" alt="">
3539 * <p>
36- * You can combine the items emitted by multiple {@code Observable}s so that they act like a single
37- * {@code Observable}, by using the merge operation.
40+ * You can combine the items emitted by multiple {@code Observable}s so that they act like a single {@code Observable}, by using the merge operation.
3841 *
3942 * @param <T>
4043 * the type of the items emitted by both the source and merged {@code Observable}s
4144 */
42- public final class OperatorMerge <T > implements Operator <T , Observable <? extends T >> {
45+ public class OperatorMerge <T > implements Operator <T , Observable <? extends T >> {
46+
47+ public OperatorMerge () {
48+ this .delayErrors = false ;
49+ }
50+
51+ public OperatorMerge (boolean delayErrors ) {
52+ this .delayErrors = delayErrors ;
53+ }
54+
55+ private final boolean delayErrors ;
4356
4457 @ Override
4558 public Subscriber <Observable <? extends T >> call (final Subscriber <? super T > child ) {
46- return new MergeSubscriber <T >(child );
59+ return new MergeSubscriber <T >(child , delayErrors );
4760
4861 }
4962
@@ -53,6 +66,8 @@ private static final class MergeSubscriber<T> extends Subscriber<Observable<? ex
5366 private final MergeProducer <T > mergeProducer ;
5467 private int wip ;
5568 private boolean completed ;
69+ private final boolean delayErrors ;
70+ private ConcurrentLinkedQueue <Throwable > exceptions ;
5671
5772 private volatile SubscriptionIndexedRingBuffer <InnerSubscriber <T >> childrenSubscribers ;
5873
@@ -77,10 +92,11 @@ private static final class MergeSubscriber<T> extends Subscriber<Observable<? ex
7792 * } </pre>
7893 */
7994
80- public MergeSubscriber (Subscriber <? super T > actual ) {
95+ public MergeSubscriber (Subscriber <? super T > actual , boolean delayErrors ) {
8196 super (actual );
8297 this .actual = actual ;
8398 this .mergeProducer = new MergeProducer <T >(this );
99+ this .delayErrors = delayErrors ;
84100 // decoupled the subscription chain because we need to decouple and control backpressure
85101 actual .add (this );
86102 actual .setProducer (mergeProducer );
@@ -337,8 +353,26 @@ public Boolean call(InnerSubscriber<T> s) {
337353
338354 @ Override
339355 public void onError (Throwable e ) {
340- actual .onError (e );
341- unsubscribe ();
356+ if (delayErrors ) {
357+ synchronized (this ) {
358+ if (exceptions == null ) {
359+ exceptions = new ConcurrentLinkedQueue <Throwable >();
360+ }
361+ }
362+ exceptions .add (e );
363+ boolean sendOnComplete = false ;
364+ synchronized (this ) {
365+ wip --;
366+ if (wip == 0 && completed ) {
367+ sendOnComplete = true ;
368+ }
369+ }
370+ if (sendOnComplete ) {
371+ drainAndComplete ();
372+ }
373+ } else {
374+ actual .onError (e );
375+ }
342376 }
343377
344378 @ Override
@@ -372,7 +406,25 @@ void completeInner(InnerSubscriber<T> s) {
372406
373407 private void drainAndComplete () {
374408 drainQueuesIfNeeded (); // TODO need to confirm whether this is needed or not
375- actual .onCompleted ();
409+ if (delayErrors ) {
410+ Queue <Throwable > es = null ;
411+ synchronized (this ) {
412+ es = exceptions ;
413+ }
414+ if (es != null ) {
415+ if (es .isEmpty ()) {
416+ actual .onCompleted ();
417+ } else if (es .size () == 1 ) {
418+ actual .onError (es .poll ());
419+ } else {
420+ actual .onError (new CompositeException (es ));
421+ }
422+ } else {
423+ actual .onCompleted ();
424+ }
425+ } else {
426+ actual .onCompleted ();
427+ }
376428 }
377429
378430 }
@@ -493,7 +545,12 @@ private void emit(T t, boolean complete) {
493545 if (complete ) {
494546 parentSubscriber .completeInner (this );
495547 } else {
496- parentSubscriber .actual .onNext (t );
548+ try {
549+ parentSubscriber .actual .onNext (t );
550+ } catch (Throwable e ) {
551+ // special error handling due to complexity of merge
552+ onError (OnErrorThrowable .addValueAsLastCause (e , t ));
553+ }
497554 emitted ++;
498555 }
499556 } else {
@@ -503,7 +560,12 @@ private void emit(T t, boolean complete) {
503560 if (complete ) {
504561 parentSubscriber .completeInner (this );
505562 } else {
506- parentSubscriber .actual .onNext (t );
563+ try {
564+ parentSubscriber .actual .onNext (t );
565+ } catch (Throwable e ) {
566+ // special error handling due to complexity of merge
567+ onError (OnErrorThrowable .addValueAsLastCause (e , t ));
568+ }
507569 emitted ++;
508570 producer .REQUESTED .decrementAndGet (producer );
509571 }
@@ -585,8 +647,13 @@ private int drainRequested() {
585647 } else if (q .isCompleted (o )) {
586648 parentSubscriber .completeInner (this );
587649 } else {
588- if (!q .accept (o , parentSubscriber .actual )) {
589- emitted ++;
650+ try {
651+ if (!q .accept (o , parentSubscriber .actual )) {
652+ emitted ++;
653+ }
654+ } catch (Throwable e ) {
655+ // special error handling due to complexity of merge
656+ onError (OnErrorThrowable .addValueAsLastCause (e , o ));
590657 }
591658 }
592659 }
@@ -604,8 +671,13 @@ private int drainAll() {
604671 if (q .isCompleted (o )) {
605672 parentSubscriber .completeInner (this );
606673 } else {
607- if (!q .accept (o , parentSubscriber .actual )) {
608- emitted ++;
674+ try {
675+ if (!q .accept (o , parentSubscriber .actual )) {
676+ emitted ++;
677+ }
678+ } catch (Throwable e ) {
679+ // special error handling due to complexity of merge
680+ onError (OnErrorThrowable .addValueAsLastCause (e , o ));
609681 }
610682 }
611683 }
0 commit comments