/** * Schedules the given runnable periodically on the underlying executor directly * and returns its future wrapped into a Disposable. * @param run the Runnable to execute in a periodic fashion * @param initialDelay the initial delay amount * @param period the repeat period amount * @param unit the time unit for both the initialDelay and period * @return the ScheduledRunnable instance */ public Disposable schedulePeriodicallyDirect(final Runnable run, long initialDelay, long period, TimeUnit unit) { ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(RxJavaCommonPlugins.onSchedule(run)); try { Future<?> f = executor.scheduleAtFixedRate(task, initialDelay, period, unit); task.setFuture(f); return task; } catch (RejectedExecutionException ex) { RxJavaCommonPlugins.onError(ex); return Scheduler.REJECTED; } }
/** * Removes all handlers and resets to default behavior. */ public static void reset() { setErrorHandler(null); setScheduleHandler(null); setComputationSchedulerHandler(null); setInitComputationSchedulerHandler(null); setIoSchedulerHandler(null); setInitIoSchedulerHandler(null); setSingleSchedulerHandler(null); setInitSingleSchedulerHandler(null); setNewThreadSchedulerHandler(null); setInitNewThreadSchedulerHandler(null); setFailOnNonBlockingScheduler(false); setOnBeforeBlocking(null); }
/** * Called when an undeliverable error occurs. * @param error the error to report */ public static void onError(@NonNull Throwable error) { Consumer<? super Throwable> f = errorHandler; if (error == null) { error = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources."); } else { if (!isBug(error)) { error = new UndeliverableException(error); } } if (f != null) { try { f.accept(error); return; } catch (Throwable e) { // Exceptions.throwIfFatal(e); TODO decide e.printStackTrace(); // NOPMD uncaught(e); } } error.printStackTrace(); // NOPMD uncaught(error); }
/** * Checks if the {@code failOnNonBlockingScheduler} plugin setting is enabled and the current * thread is a Scheduler sensitive to blocking operators. * @throws IllegalStateException if the {@code failOnNonBlockingScheduler} and the current thread is sensitive to blocking */ public static void verifyNonBlocking() { if (RxJavaCommonPlugins.isFailOnNonBlockingScheduler() && (Thread.currentThread() instanceof NonBlockingThread || RxJavaCommonPlugins.onBeforeBlocking())) { throw new IllegalStateException("Attempt to block on a Scheduler " + Thread.currentThread().getName() + " that doesn't support blocking operators as they may lead to deadlock"); } } }
RxJavaCommonPlugins.setErrorHandler(errorHandler); Consumer<? super Throwable> errorHandler1 = RxJavaCommonPlugins.getErrorHandler(); assertSame(errorHandler, errorHandler1); RxJavaCommonPlugins.setInitComputationSchedulerHandler(callable2scheduler); RxJavaCommonPlugins.setComputationSchedulerHandler(scheduler2scheduler); RxJavaCommonPlugins.setIoSchedulerHandler(scheduler2scheduler); RxJavaCommonPlugins.setNewThreadSchedulerHandler(scheduler2scheduler); RxJavaCommonPlugins.setScheduleHandler(runnable2runnable); RxJavaCommonPlugins.setSingleSchedulerHandler(scheduler2scheduler); RxJavaCommonPlugins.setInitSingleSchedulerHandler(callable2scheduler); RxJavaCommonPlugins.setInitNewThreadSchedulerHandler(callable2scheduler); RxJavaCommonPlugins.setInitIoSchedulerHandler(callable2scheduler); } finally { RxJavaCommonPlugins.reset();
@Override public void onError(Throwable t) { if (done) { RxJavaCommonPlugins.onError(t); return; } done = true; s = SubscriptionHelper.CANCELLED; actual.onError(t); }
@Test public void onErrorNull() { try { final AtomicReference<Throwable> t = new AtomicReference<Throwable>(); RxJavaCommonPlugins.setErrorHandler(new Consumer<Throwable>() { @Override public void accept(final Throwable throwable) throws Exception { t.set(throwable); } }); RxJavaCommonPlugins.onError(null); final Throwable throwable = t.get(); assertEquals("onError called with null. Null values are generally not allowed in 2.x operators and sources.", throwable.getMessage()); assertTrue(throwable instanceof NullPointerException); } finally { RxJavaCommonPlugins.reset(); } }
@Test public void clearIsPassthrough() { try { RxJavaCommonPlugins.reset(); assertNull(RxJavaCommonPlugins.onSchedule(null)); assertNull(RxJavaCommonPlugins.onSchedule(null)); assertSame(action, RxJavaCommonPlugins.onSchedule(action)); assertSame(s, RxJavaCommonPlugins.onComputationScheduler(s)); assertSame(s, RxJavaCommonPlugins.onIoScheduler(s)); assertSame(s, RxJavaCommonPlugins.onNewThreadScheduler(s)); assertSame(s, RxJavaCommonPlugins.onSingleScheduler(s)); assertSame(s, RxJavaCommonPlugins.initComputationScheduler(c)); assertSame(s, RxJavaCommonPlugins.initIoScheduler(c)); assertSame(s, RxJavaCommonPlugins.initNewThreadScheduler(c)); assertSame(s, RxJavaCommonPlugins.initSingleScheduler(c)); RxJavaCommonPlugins.reset();
@Test public void overrideComputationScheduler() { try { RxJavaCommonPlugins.setComputationSchedulerHandler(replaceWithImmediate); assertSame(ImmediateThinScheduler.INSTANCE, Schedulers.computation()); } finally { RxJavaCommonPlugins.reset(); } // make sure the reset worked assertNotSame(ImmediateThinScheduler.INSTANCE, Schedulers.computation()); }
@Test public void singleElementOperatorDoNotSwallowExceptionWhenDone() { final Throwable exception = new RuntimeException("some error"); final AtomicReference<Throwable> error = new AtomicReference<Throwable>(); try { RxJavaCommonPlugins.setErrorHandler(new Consumer<Throwable>() { @Override public void accept(final Throwable throwable) throws Exception { error.set(throwable); } }); singleElement(Flowable.unsafeCreate(new Publisher<Integer>() { @Override public void subscribe(final Subscriber<? super Integer> observer) { observer.onComplete(); observer.onError(exception); } })).test().assertComplete(); assertSame(exception, error.get().getCause()); } finally { RxJavaCommonPlugins.reset(); } }
public static List<Throwable> trackPluginErrors() { final List<Throwable> list = Collections.synchronizedList(new ArrayList<Throwable>()); RxJavaCommonPlugins.setErrorHandler(new Consumer<Throwable>() { @Override public void accept(Throwable t) { list.add(t); } }); return list; }
@Test public void onBeforeBlocking() { try { RxJavaCommonPlugins.setOnBeforeBlocking(new BooleanSupplier() { @Override public boolean getAsBoolean() throws Exception { throw new IllegalArgumentException(); } }); try { RxJavaCommonPlugins.onBeforeBlocking(); fail("Should have thrown"); } catch (IllegalArgumentException ex) { // expected } } finally { RxJavaCommonPlugins.reset(); } }
@Test public void failWithCustomHandler() { try { RxJavaCommonPlugins.setOnBeforeBlocking(new BooleanSupplier() { @Override public boolean getAsBoolean() throws Exception { RxJavaCommonPlugins.setFailOnNonBlockingScheduler(true); RxJavaCommonPlugins.reset();
@Test public void createComputationScheduler() { final String name = "ComputationSchedulerTest"; ThreadFactory factory = new ThreadFactory() { @Override public Thread newThread(Runnable r) { return new Thread(r, name); } }; final Scheduler customScheduler = RxJavaCommonPlugins.createComputationScheduler(factory); RxJavaCommonPlugins.setComputationSchedulerHandler(new Function<Scheduler, Scheduler>() { @Override public Scheduler apply(Scheduler scheduler) throws Exception { return customScheduler; } }); try { verifyThread(Schedulers.computation(), name); } finally { customScheduler.shutdown(); RxJavaCommonPlugins.reset(); } }
/** * Schedules the execution of the given task with the given delay amount. * * <p> * This method is safe to be called from multiple threads but there are no * ordering guarantees between tasks. * * @param run the task to schedule * @param delay the delay amount, non-positive values indicate non-delayed scheduling * @param unit the unit of measure of the delay amount * @return the Disposable that let's one cancel this particular delayed task. * @since 2.0 */ @NonNull public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) { final Worker w = createWorker(); final Runnable decoratedRun = RxJavaCommonPlugins.onSchedule(run); DisposeTask task = new DisposeTask(decoratedRun, w); w.schedule(task, delay, unit); return task; }
return RxJavaCommonPlugins.onNewThreadScheduler(NEW_THREAD);
return RxJavaCommonPlugins.onIoScheduler(IO);
return RxJavaCommonPlugins.onComputationScheduler(COMPUTATION);
@Test public void isBug() { assertFalse(RxJavaCommonPlugins.isBug(new RuntimeException())); assertFalse(RxJavaCommonPlugins.isBug(new IOException())); assertFalse(RxJavaCommonPlugins.isBug(new InterruptedException())); assertFalse(RxJavaCommonPlugins.isBug(new InterruptedIOException())); assertTrue(RxJavaCommonPlugins.isBug(new NullPointerException())); assertTrue(RxJavaCommonPlugins.isBug(new IllegalArgumentException())); assertTrue(RxJavaCommonPlugins.isBug(new IllegalStateException())); assertTrue(RxJavaCommonPlugins.isBug(new MissingBackpressureException())); assertTrue(RxJavaCommonPlugins.isBug(new ProtocolViolationException(""))); assertTrue(RxJavaCommonPlugins.isBug(new UndeliverableException(new TestException()))); assertTrue(RxJavaCommonPlugins.isBug(new CompositeException(new TestException()))); assertTrue(RxJavaCommonPlugins.isBug(new OnErrorNotImplementedException(new TestException()))); } }
@Override public void onError(Throwable t) { if (done) { RxJavaCommonPlugins.onError(t); return; } done = true; actual.onError(t); }