@Override
 public void call(Subscriber<? super T> subscriber) {
   if (refresh.compareAndSet(true, false)) {
     current = source.cache();
   }
   current.unsafeSubscribe(subscriber);
 }
Example #2
0
  @Test
  public void testZip() {
    Observable<String> os =
        OBSERVABLE_OF_5_INTEGERS.zip(
            OBSERVABLE_OF_5_INTEGERS,
            new Func2<Integer, Integer, String>() {

              @Override
              public String call(Integer a, Integer b) {
                return a + "-" + b;
              }
            });

    final ArrayList<String> list = new ArrayList<String>();
    os.subscribe(
        new Action1<String>() {

          @Override
          public void call(String s) {
            System.out.println(s);
            list.add(s);
          }
        });

    assertEquals(5, list.size());
    assertEquals("1-1", list.get(0));
    assertEquals("2-2", list.get(1));
    assertEquals("5-5", list.get(4));
  }
  /** IO scheduler defaults to using CachedThreadScheduler */
  @Test
  public final void testIOScheduler() {

    Observable<Integer> o1 = Observable.from(1, 2, 3, 4, 5);
    Observable<Integer> o2 = Observable.from(6, 7, 8, 9, 10);
    Observable<String> o =
        Observable.merge(o1, o2)
            .map(
                new Func1<Integer, String>() {

                  @Override
                  public String call(Integer t) {
                    assertTrue(
                        Thread.currentThread().getName().startsWith("RxCachedThreadScheduler"));
                    return "Value_" + t + "_Thread_" + Thread.currentThread().getName();
                  }
                });

    o.subscribeOn(Schedulers.io())
        .toBlocking()
        .forEach(
            new Action1<String>() {

              @Override
              public void call(String t) {
                System.out.println("t: " + t);
              }
            });
  }
  /** If the 'other' onCompletes then we unsubscribe from the source and onComplete */
  @Test
  @SuppressWarnings("unchecked")
  public void testTakeUntilOtherCompleted() {
    Subscription sSource = mock(Subscription.class);
    Subscription sOther = mock(Subscription.class);
    TestObservable source = new TestObservable(sSource);
    TestObservable other = new TestObservable(sOther);

    Observer<String> result = mock(Observer.class);
    Observable<String> stringObservable =
        Observable.create(source).takeUntil(Observable.create(other));
    stringObservable.subscribe(result);
    source.sendOnNext("one");
    source.sendOnNext("two");
    other.sendOnCompleted();
    source.sendOnNext("three");

    verify(result, times(1)).onNext("one");
    verify(result, times(1)).onNext("two");
    verify(result, times(0)).onNext("three");
    verify(result, times(1)).onCompleted();
    verify(sSource, times(1)).unsubscribe();
    verify(sOther, times(1))
        .unsubscribe(); // unsubscribed since SafeSubscriber unsubscribes after onComplete
  }
  @Test
  public void testResumeNext() {
    Subscription s = mock(Subscription.class);
    // Trigger failure on second element
    TestObservable f = new TestObservable(s, "one", "fail", "two", "three");
    Observable<String> w = Observable.create(f);
    Observable<String> resume = Observable.from("twoResume", "threeResume");
    Observable<String> observable = Observable.create(onErrorResumeNextViaObservable(w, resume));

    @SuppressWarnings("unchecked")
    Observer<String> observer = mock(Observer.class);
    observable.subscribe(observer);

    try {
      f.t.join();
    } catch (InterruptedException e) {
      fail(e.getMessage());
    }

    verify(observer, Mockito.never()).onError(any(Throwable.class));
    verify(observer, times(1)).onCompleted();
    verify(observer, times(1)).onNext("one");
    verify(observer, Mockito.never()).onNext("two");
    verify(observer, Mockito.never()).onNext("three");
    verify(observer, times(1)).onNext("twoResume");
    verify(observer, times(1)).onNext("threeResume");
  }
  /** Simple concat of 2 asynchronous observables ensuring it emits in correct order. */
  @SuppressWarnings("unchecked")
  @Test
  public void testSimpleAsyncConcat() {
    Observer<String> observer = mock(Observer.class);

    TestObservable<String> o1 = new TestObservable<String>("one", "two", "three");
    TestObservable<String> o2 = new TestObservable<String>("four", "five", "six");

    Observable.concat(Observable.create(o1), Observable.create(o2)).subscribe(observer);

    try {
      // wait for async observables to complete
      o1.t.join();
      o2.t.join();
    } catch (Throwable e) {
      throw new RuntimeException("failed waiting on threads");
    }

    InOrder inOrder = inOrder(observer);
    inOrder.verify(observer, times(1)).onNext("one");
    inOrder.verify(observer, times(1)).onNext("two");
    inOrder.verify(observer, times(1)).onNext("three");
    inOrder.verify(observer, times(1)).onNext("four");
    inOrder.verify(observer, times(1)).onNext("five");
    inOrder.verify(observer, times(1)).onNext("six");
  }
  @Test(groups = "standalone")
  public void testObserveMultiple() {
    final TestSubscriber<Response> tester = new TestSubscriber<>();

    try (AsyncHttpClient client = asyncHttpClient()) {
      Observable<Response> o1 =
          AsyncHttpObservable.observe(() -> client.prepareGet("http://gatling.io"));
      Observable<Response> o2 =
          AsyncHttpObservable.observe(
              () -> client.prepareGet("http://www.wisc.edu").setFollowRedirect(true));
      Observable<Response> o3 =
          AsyncHttpObservable.observe(
              () -> client.prepareGet("http://www.umn.edu").setFollowRedirect(true));
      Observable<Response> all = Observable.merge(o1, o2, o3);
      all.subscribe(tester);
      tester.awaitTerminalEvent();
      tester.assertTerminalEvent();
      tester.assertCompleted();
      tester.assertNoErrors();
      List<Response> responses = tester.getOnNextEvents();
      assertNotNull(responses);
      assertEquals(responses.size(), 3);
      for (Response response : responses) {
        assertEquals(response.getStatusCode(), 200);
      }
    } catch (Exception e) {
      Thread.currentThread().interrupt();
    }
  }
Example #8
0
  @SuppressWarnings({"unchecked", "RedundantCast"})
  private static Observable<Object> invokeWithRetry(
      Api api, Method method, Object[] args, Predicate<Throwable> shouldRetryTest, int retryCount)
      throws IllegalAccessException, InvocationTargetException {

    Observable<Object> result = (Observable<Object>) method.invoke(api, args);
    for (int i = 0; i < retryCount; i++) {
      result =
          result.onErrorResumeNext(
              err -> {
                if (shouldRetryTest.apply(err)) {
                  try {
                    // give the server a small grace period before trying again.
                    Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS);

                    logger.warn("perform retry, calling method {} again", method);
                    return (Observable<Object>) method.invoke(api, args);
                  } catch (Exception error) {
                    return Observable.error(error);
                  }
                } else {
                  // forward error if it is not a network problem
                  return Observable.error(err);
                }
              });
    }

    return result;
  }
Example #9
0
  // Get the image from the filesystem if it exists or download from network
  private Observable<Page> getOrDownloadImage(final Page page, Download download) {
    // If the image URL is empty, do nothing
    if (page.getImageUrl() == null) return Observable.just(page);

    String filename = getImageFilename(page);
    File imagePath = new File(download.directory, filename);

    // If the image is already downloaded, do nothing. Otherwise download from network
    Observable<Page> pageObservable =
        isImageDownloaded(imagePath)
            ? Observable.just(page)
            : downloadImage(page, download.source, download.directory, filename);

    return pageObservable
        // When the image is ready, set image path, progress (just in case) and status
        .doOnNext(
            p -> {
              page.setImagePath(imagePath.getAbsolutePath());
              page.setProgress(100);
              download.downloadedImages++;
              page.setStatus(Page.READY);
            })
        // Mark this page as error and allow to download the remaining
        .onErrorResumeNext(
            e -> {
              page.setProgress(0);
              page.setStatus(Page.ERROR);
              return Observable.just(page);
            });
  }
  @Test
  public void testBackpressureWithTakeBefore() {
    final AtomicInteger generated = new AtomicInteger();
    Observable<Integer> observable =
        Observable.from(
            new Iterable<Integer>() {
              @Override
              public Iterator<Integer> iterator() {
                return new Iterator<Integer>() {

                  @Override
                  public void remove() {}

                  @Override
                  public Integer next() {
                    return generated.getAndIncrement();
                  }

                  @Override
                  public boolean hasNext() {
                    return true;
                  }
                };
              }
            });

    TestSubscriber<Integer> testSubscriber = new TestSubscriber<Integer>();
    observable.take(7).observeOn(Schedulers.newThread()).subscribe(testSubscriber);

    testSubscriber.awaitTerminalEvent();
    testSubscriber.assertReceivedOnNext(Arrays.asList(0, 1, 2, 3, 4, 5, 6));
    assertEquals(7, generated.get());
  }
  @Test
  @SuppressWarnings("unchecked")
  public void testOrdering() throws InterruptedException {
    Observable<String> obs = Observable.just("one", null, "two", "three", "four");

    Observer<String> observer = mock(Observer.class);

    InOrder inOrder = inOrder(observer);
    TestSubscriber<String> ts = new TestSubscriber<String>(observer);

    obs.observeOn(Schedulers.computation()).subscribe(ts);

    ts.awaitTerminalEvent(1000, TimeUnit.MILLISECONDS);
    if (ts.getOnErrorEvents().size() > 0) {
      for (Throwable t : ts.getOnErrorEvents()) {
        t.printStackTrace();
      }
      fail("failed with exception");
    }

    inOrder.verify(observer, times(1)).onNext("one");
    inOrder.verify(observer, times(1)).onNext(null);
    inOrder.verify(observer, times(1)).onNext("two");
    inOrder.verify(observer, times(1)).onNext("three");
    inOrder.verify(observer, times(1)).onNext("four");
    inOrder.verify(observer, times(1)).onCompleted();
    inOrder.verifyNoMoreInteractions();
  }
  @Test
  public void observeOnTheSameSchedulerTwice() {
    Scheduler scheduler = Schedulers.immediate();

    Observable<Integer> o = Observable.just(1, 2, 3);
    Observable<Integer> o2 = o.observeOn(scheduler);

    @SuppressWarnings("unchecked")
    Observer<Object> observer1 = mock(Observer.class);
    @SuppressWarnings("unchecked")
    Observer<Object> observer2 = mock(Observer.class);

    InOrder inOrder1 = inOrder(observer1);
    InOrder inOrder2 = inOrder(observer2);

    o2.subscribe(observer1);
    o2.subscribe(observer2);

    inOrder1.verify(observer1, times(1)).onNext(1);
    inOrder1.verify(observer1, times(1)).onNext(2);
    inOrder1.verify(observer1, times(1)).onNext(3);
    inOrder1.verify(observer1, times(1)).onCompleted();
    verify(observer1, never()).onError(any(Throwable.class));
    inOrder1.verifyNoMoreInteractions();

    inOrder2.verify(observer2, times(1)).onNext(1);
    inOrder2.verify(observer2, times(1)).onNext(2);
    inOrder2.verify(observer2, times(1)).onNext(3);
    inOrder2.verify(observer2, times(1)).onCompleted();
    verify(observer2, never()).onError(any(Throwable.class));
    inOrder2.verifyNoMoreInteractions();
  }
Example #13
0
  /** One time setup of the FFmpeg library. */
  public Observable<Void> setupFFmpeg() {
    if (!firstSetup.get()) return Observable.just(null);
    firstSetup.set(false);
    return Observable.create(
        new Observable.OnSubscribe<Void>() {
          @Override
          public void call(final Subscriber<? super Void> subscriber) {
            LoadBinaryResponseHandler responseHandler =
                new LoadBinaryResponseHandler() {
                  @Override
                  public void onFailure() {
                    if (subscriber.isUnsubscribed()) return;
                    subscriber.onError(new IllegalStateException("failed to load FFmpeg binaries"));
                  }

                  @Override
                  public void onSuccess() {
                    if (subscriber.isUnsubscribed()) return;
                    subscriber.onNext(null);
                    subscriber.onCompleted();
                  }
                };

            try {
              fFmpeg.loadBinary(responseHandler);
            } catch (FFmpegNotSupportedException e) {
              subscriber.onError(e);
            }
          }
        });
  }
Example #14
0
    @Test
    public void testDebounceNeverEmits() {
      Observable<String> source =
          Observable.create(
              new OnSubscribeFunc<String>() {
                @Override
                public Subscription onSubscribe(Observer<? super String> observer) {
                  // all should be skipped since they are happening faster than the 200ms timeout
                  publishNext(observer, 100, "a"); // Should be skipped
                  publishNext(observer, 200, "b"); // Should be skipped
                  publishNext(observer, 300, "c"); // Should be skipped
                  publishNext(observer, 400, "d"); // Should be skipped
                  publishNext(observer, 500, "e"); // Should be skipped
                  publishNext(observer, 600, "f"); // Should be skipped
                  publishNext(observer, 700, "g"); // Should be skipped
                  publishNext(observer, 800, "h"); // Should be skipped
                  publishCompleted(
                      observer, 900); // Should be published as soon as the timeout expires.

                  return Subscriptions.empty();
                }
              });

      Observable<String> sampled =
          Observable.create(
              OperationDebounce.debounce(source, 200, TimeUnit.MILLISECONDS, scheduler));
      sampled.subscribe(observer);

      scheduler.advanceTimeTo(0, TimeUnit.MILLISECONDS);
      InOrder inOrder = inOrder(observer);
      inOrder.verify(observer, times(0)).onNext(anyString());
      scheduler.advanceTimeTo(1000, TimeUnit.MILLISECONDS);
      inOrder.verify(observer, times(1)).onCompleted();
      inOrder.verifyNoMoreInteractions();
    }
Example #15
0
 Object apply(
     final Object[] args, final TProtocol protocol, final int seqid, Scheduler subscribScheduler)
     throws Exception {
   if (isObservable) {
     Observable observable =
         Observable.create(
             new Observable.OnSubscribe<Object>() {
               @Override
               public void call(Subscriber<? super Object> subscriber) {
                 try {
                   if (subscriber.isUnsubscribed()) {
                     return;
                   }
                   subscriber.onNext(FunctionCall.this.sendAndRecv(args, protocol, seqid));
                   subscriber.onCompleted();
                 } catch (Exception e) {
                   subscriber.onError(e);
                 }
               }
             });
     if (null != subscribScheduler) return observable.subscribeOn(subscribScheduler);
     else return observable;
   }
   return sendAndRecv(args, protocol, seqid);
 }
 /** Bind view on immediate scheduler. */
 public static <T> Observable<T> bindViewImmediate(View view, Observable<T> source) {
   if (view == null || source == null)
     throw new IllegalArgumentException("View and Observable must be given");
   return source
       .takeUntil(Observable.create(new OnSubscribeViewDetachedFromWindowFirst(view)))
       .observeOn(Schedulers.immediate());
 }
Example #17
0
    @Test
    public void testZippingDifferentLengthObservableSequences2() {
      @SuppressWarnings("unchecked")
      Observer<String> w = mock(Observer.class);

      TestObservable w1 = new TestObservable();
      TestObservable w2 = new TestObservable();
      TestObservable w3 = new TestObservable();

      Observable<String> zipW = Observable.create(zip(w1, w2, w3, getConcat3StringsZipr()));
      zipW.subscribe(w);

      /* simulate sending data */
      // 4 times for w1
      w1.Observer.onNext("1a");
      w1.Observer.onNext("1b");
      w1.Observer.onNext("1c");
      w1.Observer.onNext("1d");
      w1.Observer.onCompleted();
      // twice for w2
      w2.Observer.onNext("2a");
      w2.Observer.onNext("2b");
      w2.Observer.onCompleted();
      // 1 times for w3
      w3.Observer.onNext("3a");
      w3.Observer.onCompleted();

      /* we should have been called 1 time on the Observer */
      InOrder inOrder = inOrder(w);
      inOrder.verify(w).onNext("1a2a3a");

      inOrder.verify(w, times(1)).onCompleted();
    }
Example #18
0
  public static void main(String[] args) {
    Common.init("Hello RxJava");

    Observable<String> tweets =
        Observable.just("Hello RxJava!", "RxJava is fun!!", "RxJava rocks!!!");
    tweets.subscribe((s) -> System.out.println(s));
  }
Example #19
0
  @Test
  public void concatVeryLongObservableOfObservablesTakeHalf() {
    final int n = 10000;
    Observable<Observable<Integer>> source =
        Observable.create(
            new OnSubscribe<Observable<Integer>>() {
              @Override
              public void call(Subscriber<? super Observable<Integer>> s) {
                for (int i = 0; i < n; i++) {
                  if (s.isUnsubscribed()) {
                    return;
                  }
                  s.onNext(Observable.from(i));
                }
                s.onCompleted();
              }
            });

    Observable<List<Integer>> result = Observable.concat(source).take(n / 2).toList();

    Observer<List<Integer>> o = mock(Observer.class);
    InOrder inOrder = inOrder(o);

    result.subscribe(o);

    List<Integer> list = new ArrayList<Integer>(n);
    for (int i = 0; i < n / 2; i++) {
      list.add(i);
    }
    inOrder.verify(o).onNext(list);
    inOrder.verify(o).onCompleted();
    verify(o, never()).onError(any(Throwable.class));
  }
Example #20
0
  private static void test4() {
    log("just subscribe to see output ");
    Observable<List<Integer>> listOfInts =
        Observable.just(Arrays.asList(1, 3, 5, 7), Arrays.asList(2, 4, 6, 8));
    listOfInts.subscribe(x -> System.out.print(x + " "));
    println("");

    log("concatMap");
    listOfInts.concatMap(x -> Observable.from(x)).subscribe(Main::print);
    println("");

    log("flapMap");
    listOfInts
        .flatMap(
            listOfIntegers -> {
              return Observable.from(listOfIntegers);
            })
        .subscribe(Main::print);
    println("");

    Map<String, List<Integer>> m1 = new HashMap<>();
    m1.put("key", Arrays.asList(2, 4, 6, 8, 10));

    Map<String, List<Integer>> m2 = new HashMap<>();
    m2.put("key", Arrays.asList(1, 3, 5, 7, 9));

    log("testing flatMap with 2 maps param");
    Observable.just(m1, m2)
        .flatMap(map -> Observable.from(map.get("key")).map(x -> x))
        .subscribe(Main::print);
    println("");
  }
  @Test
  public void testSkipTimedFinishBeforeTime() {
    TestScheduler scheduler = new TestScheduler();

    PublishSubject<Integer> source = PublishSubject.create();

    Observable<Integer> result = source.skip(1, TimeUnit.SECONDS, scheduler);

    Observer<Object> o = mock(Observer.class);

    result.subscribe(o);

    source.onNext(1);
    source.onNext(2);
    source.onNext(3);
    source.onCompleted();

    scheduler.advanceTimeBy(1, TimeUnit.SECONDS);

    InOrder inOrder = inOrder(o);

    inOrder.verify(o).onCompleted();
    inOrder.verifyNoMoreInteractions();
    verify(o, never()).onNext(any());
    verify(o, never()).onError(any(Throwable.class));
  }
  public Observable<List<TwitterUser>> searchUsers(String prefix) {
    if (ThreadLocalRandom.current().nextDouble() < failureProbability) {
      return Observable.error(new IOException("Broken pipe"));
    }

    return Observable.from(users).skip(1).toList().subscribeOn(Schedulers.newThread());
  }
  @Test
  @SuppressWarnings("unchecked")
  public void testTakeUntilSourceError() {
    Subscription sSource = mock(Subscription.class);
    Subscription sOther = mock(Subscription.class);
    TestObservable source = new TestObservable(sSource);
    TestObservable other = new TestObservable(sOther);
    Throwable error = new Throwable();

    Observer<String> result = mock(Observer.class);
    Observable<String> stringObservable =
        Observable.create(source).takeUntil(Observable.create(other));
    stringObservable.subscribe(result);
    source.sendOnNext("one");
    source.sendOnNext("two");
    source.sendOnError(error);
    source.sendOnNext("three");

    verify(result, times(1)).onNext("one");
    verify(result, times(1)).onNext("two");
    verify(result, times(0)).onNext("three");
    verify(result, times(1)).onError(error);
    verify(sSource, times(1)).unsubscribe();
    verify(sOther, times(1)).unsubscribe();
  }
  @Test
  public void testSingleWithBackpressure() {
    Observable<Integer> observable = Observable.just(1, 2).single();

    Subscriber<Integer> subscriber =
        spy(
            new Subscriber<Integer>() {

              @Override
              public void onStart() {
                request(1);
              }

              @Override
              public void onCompleted() {}

              @Override
              public void onError(Throwable e) {}

              @Override
              public void onNext(Integer integer) {
                request(1);
              }
            });
    observable.subscribe(subscriber);

    InOrder inOrder = inOrder(subscriber);
    inOrder.verify(subscriber, times(1)).onError(isA(IllegalArgumentException.class));
    inOrder.verifyNoMoreInteractions();
  }
  public void importGDMModel(final String filePath) throws IOException {

    final Observable<Resource> gdmModel = getGDMModel(filePath);

    gdmModel
        .map(
            resource -> {
              try {

                processGDMResource(resource);
              } catch (final Exception e) {

                final String message = "something went wrong while processing this resource";

                LOG.error(message, e);

                throw WikidataImporterError.wrap(new WikidataImporterException(message, e));
              }

              return resource;
            })
        .toBlocking()
        .lastOrDefault(null);

    // TODO: return Observable (?)
  }
Example #26
0
  private Observable<Item> searchByHashtagObservable() {
    Observable<Item> observableSocialNetworks =
        Observable.from(socialNetworks)
            .flatMap(
                new Func1<SocialNetwork, Observable<Item>>() {
                  @Override
                  public Observable<Item> call(SocialNetwork socialNetwork) {
                    return socialNetwork.getService().searchByHashtag(hashtag);
                  }
                });

    List<Observable<Item>> observableList = Lists.newArrayList();
    observableList.add(observableSocialNetworks);

    return Observable.zip(
        observableList,
        new FuncN<Item>() {

          @Override
          public Item call(Object... args) {
            if (args.length == 1) {
              return (Item) args[0];
            }
            return Item.empty();
          }
        });
  }
Example #27
0
  @Test
  public void testEmitNull() {
    Observable<Integer> oi = Observable.from(1, null, 3);
    Observable<String> os = Observable.from("a", "b", null);
    Observable<String> o =
        Observable.zip(
            oi,
            os,
            new Func2<Integer, String, String>() {

              @Override
              public String call(Integer t1, String t2) {
                return t1 + "-" + t2;
              }
            });

    final ArrayList<String> list = new ArrayList<String>();
    o.subscribe(
        new Action1<String>() {

          @Override
          public void call(String s) {
            System.out.println(s);
            list.add(s);
          }
        });

    assertEquals(3, list.size());
    assertEquals("1-a", list.get(0));
    assertEquals("null-b", list.get(1));
    assertEquals("3-null", list.get(2));
  }
Example #28
0
  public static void main(String[] args) {

    // A basic Observable that emits "Hello World" when someone subscribes to it
    Observable<String> simpleObservable =
        Observable.create(
            new Observable.OnSubscribe<String>() {

              @Override
              public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("Hello, world");
                subscriber.onCompleted();
              }
            });

    // A basic Subscriber to consume the data. All it does is emit a string emitted by the
    // observable
    Subscriber<String> simpleSubscriber =
        new Subscriber<String>() {
          @Override
          public void onCompleted() {}

          @Override
          public void onError(Throwable throwable) {}

          @Override
          public void onNext(String s) {
            System.out.println(s);
          }
        };

    simpleObservable.subscribe(simpleSubscriber);
  }
Example #29
0
  @Test
  public void testUnsubscribeAfterTake() {
    final Subscription s = mock(Subscription.class);
    TestObservableFunc f = new TestObservableFunc("one", "two", "three");
    Observable<String> w = Observable.create(f);

    @SuppressWarnings("unchecked")
    Observer<String> observer = mock(Observer.class);

    Subscriber<String> subscriber = Subscribers.from(observer);
    subscriber.add(s);

    Observable<String> take = w.lift(new OperatorTake<String>(1));
    take.subscribe(subscriber);

    // wait for the Observable to complete
    try {
      f.t.join();
    } catch (Throwable e) {
      e.printStackTrace();
      fail(e.getMessage());
    }

    System.out.println("TestObservable thread finished");
    verify(observer, times(1)).onNext("one");
    verify(observer, never()).onNext("two");
    verify(observer, never()).onNext("three");
    verify(observer, times(1)).onCompleted();
    verify(s, times(1)).unsubscribe();
    verifyNoMoreInteractions(observer);
  }
    @Override
    public void onError(Throwable e) {
      long p = produced;
      if (p != 0L) {
        arbiter.produced(p);
      }

      Observable<T> o;

      try {
        o = onError.call(e);
      } catch (Throwable ex) {
        Exceptions.throwIfFatal(ex);

        actual.onError(new CompositeException(e, ex));

        return;
      }

      if (o == null) {
        actual.onError(
            new NullPointerException("The onError function returned a null Observable."));
      } else {
        o.unsafeSubscribe(new ResumeSubscriber<T>(actual, arbiter));
      }
    }