@Override public Subscription onSubscribe(Observer<? super TResult> t1) { VirtualList<TIntermediate> values; Throwable error; state.lock(); try { if (!state.done) { state.onSubscription.call(); return state.addReplayer(t1); } values = state.values; error = state.error; } finally { state.unlock(); } // fully replay the subject for (int i = values.start(); i < values.end(); i++) { try { t1.onNext(state.resultSelector.call(values.get(i))); } catch (Throwable t) { t1.onError(t); return Subscriptions.empty(); } } if (error != null) { t1.onError(error); } else { t1.onCompleted(); } return Subscriptions.empty(); }
@Override public void onCompleted() { parentCompleted = true; // this *can* occur before the children are done, so if it does we won't send onCompleted // but will let the child worry about it // if however this completes and there are no children processing, then we will send // onCompleted if (childObservers.size() == 0) { if (!stopped.get()) { if (ourSubscription.stop()) { if (onErrorReceived.size() == 1) { // an onError was received from 1 ChildObserver so we now send it as a delayed error actualObserver.onError(onErrorReceived.peek()); } else if (onErrorReceived.size() > 1) { // an onError was received from more than 1 ChildObserver so we now send it as a // delayed error actualObserver.onError(new CompositeException(onErrorReceived)); } else { // no delayed error so send onCompleted actualObserver.onCompleted(); } } } } }
/** * onComplete and onError when called need to check for the parent being complete and if so * send the onCompleted or onError to the actualObserver. * * <p>This does NOT get invoked if synchronous execution occurs, but will when asynchronously * executing. * * <p>TestCase testErrorDelayed4WithThreading specifically tests this use case. */ private void finishObserver() { if (childObservers.size() == 0 && parentCompleted) { if (ourSubscription.stop()) { // this thread 'won' the race to unsubscribe/stop so let's send onError or onCompleted if (onErrorReceived.size() == 1) { // an onError was received from 1 ChildObserver so we now send it as a delayed error actualObserver.onError(onErrorReceived.peek()); } else if (onErrorReceived.size() > 1) { // an onError was received from more than 1 ChildObserver so we now send it as a // delayed error actualObserver.onError(new CompositeException(onErrorReceived)); } else { // no delayed error so send onCompleted actualObserver.onCompleted(); } } } }
@Override public void onError(Exception e) { if (!stopped.get()) { if (ourSubscription.stop()) { // this thread 'won' the race to unsubscribe/stop so let's send the error actualObserver.onError(e); } } }
@Override public void onError(Throwable e) { /* * Cancel previous subscription if it has not already executed. * Expected that some race-condition will occur as this is crossing over thread boundaries * We are using SynchronizedObserver around 'observer' to handle interleaving and out-of-order calls. */ lastScheduledNotification.get().unsubscribe(); observer.onError(e); }
/** * Replay up to the given index * * @param limit */ void replayTill(int limit) { int si = values.start(); if (index < si) { index = si; } while (index < limit) { TIntermediate value = values.get(index); index++; try { wrapped.onNext(resultSelector.call(value)); } catch (Throwable t) { replayers.remove(cancel); wrapped.onError(t); return; } } if (done) { if (error != null) { wrapped.onError(error); } else { wrapped.onCompleted(); } } }
@Override public Subscription subscribe(Observer<String> observer) { for (String s : valuesToReturn) { if (s == null) { System.out.println("throwing exception"); observer.onError(new NullPointerException()); } else { observer.onNext(s); } } observer.onCompleted(); return new Subscription() { @Override public void unsubscribe() { // unregister ... will never be called here since we are executing synchronously } }; }
/* used to simulate subscription */ public void sendOnError(Throwable e) { observer.onError(e); }
@Override public void onError(Throwable e) { observer.onError(e); }
@Override public void onError(Throwable e) { drainIfNeededAndSwitchToActual(); actual.onError(e); }
@Override public void onError(Exception e) { observer.onError(e); }
/** * @param stageObserver * @param type * @param currentStage * @param method * @param target * @param args * @return * @throws Throwable */ public static <T> Object invoke( final Observer<StageChange> stageObserver, final String currentStage, final Class<T> type, final T target, final Method method, final Object... args) throws Throwable { try { return method.invoke(target, args); } catch (Throwable t) { if (stageObserver != null) stageObserver.onNext( new StageChangeImpl(target.getClass(), target, Stage.FAILING, currentStage)); if (t instanceof InvocationTargetException) t = t.getCause(); for (Map.Entry<Method, Staged> entry : findEventHandlers(type, StageEvent.BEFORE_FAIL).entrySet()) { if (target == null && !Modifier.isStatic(entry.getKey().getModifiers())) { LOG.warn( "Can't invoke non-static 'on=" + StageEvent.BEFORE_FAIL + "' method: " + toSignatureString(entry.getKey()), t); continue; } LOG.trace( "Calling 'on=" + StageEvent.BEFORE_FAIL + "' method: " + toSignatureString(method)); try { if (entry.getKey().getParameterTypes().length == 0) entry.getKey().invoke(target); else if (entry.getKey().getParameterTypes()[0].isAssignableFrom(t.getClass())) entry.getKey().invoke(target, t); else LOG.error( "Signature of 'on=" + StageEvent.BEFORE_FAIL + "' method: " + toSignatureString(entry.getKey()) + " does not match parameter: " + t.getClass().getName()); } catch (Throwable t2) { if (t2 instanceof InvocationTargetException) t2 = t2.getCause(); LOG.error( "Uncaught errors for 'on=" + StageEvent.BEFORE_FAIL + "' method: " + toSignatureString(entry.getKey()), t2); } } if (stageObserver != null) { stageObserver.onNext( new StageChangeImpl(target.getClass(), target, Stage.FAILED, currentStage)); if (stageObserver != null) stageObserver.onError(t); } for (Class<? extends Throwable> sup : findAbsorptionLevels(target.getClass(), method)) if (sup.isAssignableFrom(t.getClass())) { LOG.trace("Absorbed " + t.getClass().getSimpleName() + ": " + t.getMessage()); return t; } throw t; } }
@Override public void onError(Throwable e) { if (counter.getAndSet(num) < num) { observer.onError(e); } }
/* used to simulate subscription */ @SuppressWarnings("unused") public void sendOnError(Exception e) { observer.onError(e); }