@Test public void deferredResultSubscriberWithError() throws Exception { IllegalStateException ex = new IllegalStateException(); // Mono MonoProcessor<String> mono = MonoProcessor.create(); testDeferredResultSubscriber(mono, Mono.class, forClass(String.class), () -> mono.onError(ex), ex); // RxJava 1 Single AtomicReference<SingleEmitter<String>> ref = new AtomicReference<>(); Single<String> single = Single.fromEmitter(ref::set); testDeferredResultSubscriber(single, Single.class, forClass(String.class), () -> ref.get().onError(ex), ex); // RxJava 2 Single AtomicReference<io.reactivex.SingleEmitter<String>> ref2 = new AtomicReference<>(); io.reactivex.Single<String> single2 = io.reactivex.Single.create(ref2::set); testDeferredResultSubscriber(single2, io.reactivex.Single.class, forClass(String.class), () -> ref2.get().onError(ex), ex); }
@Test public void deferredResultSubscriberWithOneValue() throws Exception { // Mono MonoProcessor<String> mono = MonoProcessor.create(); testDeferredResultSubscriber(mono, Mono.class, forClass(String.class), () -> mono.onNext("foo"), "foo"); // Mono empty MonoProcessor<String> monoEmpty = MonoProcessor.create(); testDeferredResultSubscriber(monoEmpty, Mono.class, forClass(String.class), monoEmpty::onComplete, null); // RxJava 1 Single AtomicReference<SingleEmitter<String>> ref = new AtomicReference<>(); Single<String> single = Single.fromEmitter(ref::set); testDeferredResultSubscriber(single, Single.class, forClass(String.class), () -> ref.get().onSuccess("foo"), "foo"); // RxJava 2 Single AtomicReference<io.reactivex.SingleEmitter<String>> ref2 = new AtomicReference<>(); io.reactivex.Single<String> single2 = io.reactivex.Single.create(ref2::set); testDeferredResultSubscriber(single2, io.reactivex.Single.class, forClass(String.class), () -> ref2.get().onSuccess("foo"), "foo"); }
private <R> Single<R> doRequest(final Callable<DcpRequestBuilder> requestBuilder, final Func1<ByteBuf, R> resultExtractor) { return Single.fromEmitter(new Action1<SingleEmitter<R>>() { @Override public void call(final SingleEmitter<R> singleEmitter) {
/** * Executes the composite operation until the operation successfully returns and the precondition is met. * The precondition receives the composite result of the operation. */ @SuppressWarnings("HardCodedStringLiteral") public static Completable repeatCompositeUntil(Dispatcher dispatcher, int timeout, Composite composite, @Nullable Predicate<CompositeResult> until) { logger.debug("Repeat {} using {} seconds as timeout", composite, timeout); Single<CompositeResult> execution = Single.fromEmitter(em -> dispatcher.execute(composite, em::onSuccess, (op, fail) -> em.onSuccess(compositeFailure("Dispatcher failure: " + fail)), (op, ex) -> em.onSuccess(compositeFailure("Dispatcher exception: " + ex.getMessage())))); if (until == null) { until = r -> r.stream().noneMatch(ModelNode::isFailure); // default: until success } return Observable .interval(INTERVAL, MILLISECONDS) // execute a operation each INTERVAL millis .doOnEach(n -> logger.debug("#{}: execute {}", n.getValue(), composite)) .flatMapSingle(n -> execution, false, 1) .takeUntil(until::test) // until succeeded .toCompletable().timeout(timeout, SECONDS); // wait succeeded or stop after timeout seconds }
private Single<ModelNode> uploadFormData(FormData formData, Operation operation) { return Single.fromEmitter(emitter -> { XMLHttpRequest xhr = newDmrXhr(endpoints.upload(), POST, operation, new UploadPayloadProcessor(), emitter::onSuccess, (op, fail) -> emitter.onError(new DispatchFailure(fail, operation)), (op, error) -> emitter.onError(error)); xhr.send(formData); // Uploads are not supported in macros! }); }
/** * Executes the operation until the operation successfully returns and the precondition is met. The precondition * receives the result of the operation. */ @SuppressWarnings("HardCodedStringLiteral") public static Completable repeatOperationUntil(Dispatcher dispatcher, int timeout, Operation operation, @Nullable Predicate<ModelNode> until) { logger.debug("Repeat {} using {} seconds timeout", operation.asCli(), timeout); Single<ModelNode> execution = Single.fromEmitter(em -> dispatcher.execute(operation, em::onSuccess, (op, fail) -> em.onSuccess(operationFailure("Dispatcher failure: " + fail)), (op, ex) -> em.onSuccess(operationFailure("Dispatcher exception: " + ex.getMessage())))); if (until == null) { until = r -> !r.isFailure(); // default: until success } return Observable .interval(INTERVAL, MILLISECONDS) // execute a operation each INTERVAL millis .doOnEach(n -> logger.debug("#{}: execute {}", n.getValue(), operation.asCli())) .flatMapSingle(n -> execution, false, 1) .takeUntil(until::test) // until succeeded .toCompletable().timeout(timeout, SECONDS); // wait succeeded or stop after timeout seconds }
/** * Creates Single based on emitter object. Emitter activated on subscribe() call and then configured to: * - produce event+complete on successful execution of REST call * - produce error if something goes wrong during construction OR call execution * * Also RestClientRequest is wrapped in custom class that denies override of exception handler * to make sure error is handled in rx way * * @return "cold" Single that emits rest call result */ @Override public <T> Single<RestClientResponse<T>> request(HttpMethod method, String uri, Class<T> responseClass, Action1<RestClientRequest<T>> requestBuilder) { return Single.fromEmitter(emitter -> { final RestClientRequest<T> callbackRequest = restClient.request(method, uri, responseClass, restClientResponse -> emitter.onSuccess(new DefaultRxRestClientResponse<>(restClientResponse))) .exceptionHandler(emitter::onError); try { final DefaultRxRestClientRequest<T> rxDecoratedRequest = new DefaultRxRestClientRequest<>(callbackRequest); requestBuilder.call(rxDecoratedRequest); } catch (Exception e) { emitter.onError(e); } }); } }
private Single<ModelNode> dmr(Operation operation) { Operation dmrOperation = runAs(operation); // runAs might mutate the operation, so do it synchronously boolean get = GetOperation.isSupported(dmrOperation.getName()); String url = get ? operationUrl(dmrOperation) : endpoints.dmr(); HttpMethod method = get ? GET : POST; // ^-- those eager fields are useful if we don't want to evaluate it on each Single subscription return Single.fromEmitter(emitter -> { // in general, code inside the RX type should be able to be executed multiple times and always returns // the same result, so we need to be careful to not mutate anything (like the operation). This is useful // for example if we want to use the retry operator which will try again (subscribe again) if it fails. XMLHttpRequest xhr = newDmrXhr(url, method, dmrOperation, new DmrPayloadProcessor(), emitter::onSuccess, (op, fail) -> emitter.onError(new DispatchFailure(fail, operation)), (op, error) -> emitter.onError(error)); xhr.setRequestHeader(ACCEPT.header(), APPLICATION_DMR_ENCODED); xhr.setRequestHeader(CONTENT_TYPE.header(), APPLICATION_DMR_ENCODED); if (get) { xhr.send(); } else { xhr.send(dmrOperation.toBase64String()); } recordOperation(operation); }); }