@MessageMapping("mono") public Mono<String> handleMono() { this.mono = MonoProcessor.create(); return this.mono; }
private Mono<Void> executeInternal(URI url, HttpHeaders headers, WebSocketHandler handler) { MonoProcessor<Void> completionMono = MonoProcessor.create(); return Mono.fromCallable( () -> { if (logger.isDebugEnabled()) { logger.debug("Connecting to " + url); } Object jettyHandler = createHandler(url, handler, completionMono); ClientUpgradeRequest request = new ClientUpgradeRequest(); request.setSubProtocols(handler.getSubProtocols()); UpgradeListener upgradeListener = new DefaultUpgradeListener(headers); return this.jettyClient.connect(jettyHandler, url, request, upgradeListener); }) .then(completionMono); }
private Mono<Void> executeInternal(URI url, HttpHeaders requestHeaders, WebSocketHandler handler) { MonoProcessor<Void> completionMono = MonoProcessor.create(); return Mono.fromCallable( () -> { if (logger.isDebugEnabled()) { logger.debug("Connecting to " + url); } List<String> protocols = handler.getSubProtocols(); DefaultConfigurator configurator = new DefaultConfigurator(requestHeaders); Endpoint endpoint = createEndpoint(url, handler, completionMono, configurator); ClientEndpointConfig config = createEndpointConfig(configurator, protocols); return this.webSocketContainer.connectToServer(endpoint, config, url); }) .subscribeOn(Schedulers.elastic()) // connectToServer is blocking .then(completionMono); }
private Mono<Void> executeInternal(URI url, HttpHeaders headers, WebSocketHandler handler) { MonoProcessor<Void> completion = MonoProcessor.create(); return Mono.fromCallable( () -> { if (logger.isDebugEnabled()) { logger.debug("Connecting to " + url); } List<String> protocols = handler.getSubProtocols(); ConnectionBuilder builder = createConnectionBuilder(url); DefaultNegotiation negotiation = new DefaultNegotiation(protocols, headers, builder); builder.setClientNegotiation(negotiation); return builder.connect().addNotifier( new IoFuture.HandlingNotifier<WebSocketChannel, Object>() { @Override public void handleDone(WebSocketChannel channel, Object attachment) { handleChannel(url, handler, completion, negotiation, channel); } @Override public void handleFailed(IOException ex, Object attachment) { completion.onError(new IllegalStateException("Failed to connect to " + url, ex)); } }, null); }) .then(completion); }
/** * Invoke the method for the given exchange. * @param exchange the current exchange * @param bindingContext the binding context to use * @param providedArgs optional list of argument values to match by type * @return a Mono with a {@link HandlerResult}. * @throws ServerErrorException if method argument resolution or method invocation fails */ @Nullable public HandlerResult invokeForHandlerResult(ServerWebExchange exchange, BindingContext bindingContext, Object... providedArgs) { MonoProcessor<HandlerResult> processor = MonoProcessor.create(); this.delegate.invoke(exchange, bindingContext, providedArgs).subscribeWith(processor); if (processor.isTerminated()) { Throwable ex = processor.getError(); if (ex != null) { throw (ex instanceof ServerErrorException ? (ServerErrorException) ex : new ServerErrorException("Failed to invoke: " + getShortLogMessage(), getMethod(), ex)); } return processor.peek(); } else { // Should never happen... throw new IllegalStateException( "SyncInvocableHandlerMethod should have completed synchronously."); } }
@Test public void deferredResultSubscriberWithNoValues() throws Exception { MonoProcessor<String> monoEmpty = MonoProcessor.create(); testDeferredResultSubscriber(monoEmpty, Mono.class, forClass(String.class), monoEmpty::onComplete, null); }
private StatusAssertions statusAssertions(HttpStatus status) { MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/")); MockClientHttpResponse response = new MockClientHttpResponse(status); MonoProcessor<byte[]> emptyContent = MonoProcessor.create(); emptyContent.onComplete(); ExchangeResult result = new ExchangeResult(request, response, emptyContent, emptyContent, Duration.ZERO, null); return new StatusAssertions(result, mock(WebTestClient.ResponseSpec.class)); }
@Test public void customHeader() throws Exception { HttpHeaders headers = new HttpHeaders(); headers.add("my-header", "my-value"); MonoProcessor<Object> output = MonoProcessor.create(); this.client.execute(getUrl("/custom-header"), headers, session -> session.receive() .map(WebSocketMessage::getPayloadAsText) .subscribeWith(output) .then()) .block(TIMEOUT); assertEquals("my-header:my-value", output.block(TIMEOUT)); }
@Override public ListenableFuture<Void> connect(TcpConnectionHandler<P> handler, ReconnectStrategy strategy) { Assert.notNull(handler, "TcpConnectionHandler is required"); Assert.notNull(strategy, "ReconnectStrategy is required"); if (this.stopping) { return handleShuttingDownConnectFailure(handler); } // Report first connect to the ListenableFuture MonoProcessor<Void> connectMono = MonoProcessor.create(); this.tcpClient .handle(new ReactorNettyHandler(handler)) .connect() .doOnNext(updateConnectMono(connectMono)) .doOnError(updateConnectMono(connectMono)) .doOnError(handler::afterConnectFailure) // report all connect failures to the handler .flatMap(Connection::onDispose) // post-connect issues .retryWhen(reconnectFunction(strategy)) .repeatWhen(reconnectFunction(strategy)) .subscribe(); return new MonoToListenableFutureAdapter<>(connectMono); }
@Test public void MonoProcessorSuccessDoOnTerminate() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicInteger invoked = new AtomicInteger(); mp.doOnTerminate(invoked::incrementAndGet).subscribe(); mp.onNext("test"); assertThat(invoked.get()).isEqualTo(1); assertThat(mp.isSuccess()).isTrue(); assertThat(mp.isError()).isFalse(); }
private HeaderAssertions headerAssertions(HttpHeaders responseHeaders) { MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/")); MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK); response.getHeaders().putAll(responseHeaders); MonoProcessor<byte[]> emptyContent = MonoProcessor.create(); emptyContent.onComplete(); ExchangeResult result = new ExchangeResult(request, response, emptyContent, emptyContent, Duration.ZERO, null); return new HeaderAssertions(result, mock(WebTestClient.ResponseSpec.class)); }
@Test public void resolveWithMono() { BindingResult bindingResult = createBindingResult(new Foo(), "foo"); MonoProcessor<BindingResult> monoProcessor = MonoProcessor.create(); monoProcessor.onNext(bindingResult); this.bindingContext.getModel().asMap().put(BindingResult.MODEL_KEY_PREFIX + "foo", monoProcessor); MethodParameter parameter = this.testMethod.arg(Errors.class); Object actual = this.resolver.resolveArgument(parameter, this.bindingContext, this.exchange) .block(Duration.ofMillis(5000)); assertSame(bindingResult, actual); }
@Test public void MonoProcessorSuccessDoOnSuccessOrError() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicReference<String> ref = new AtomicReference<>(); mp.doOnSuccessOrError((s, f) -> ref.set(s)).subscribe(); mp.onNext("test"); assertThat(ref.get()).isEqualToIgnoringCase("test"); assertThat(mp.isSuccess()).isTrue(); assertThat(mp.isError()).isFalse(); }
MonoProcessor<BindingResult> bindingResultMono = MonoProcessor.create(); model.put(BindingResult.MODEL_KEY_PREFIX + name, bindingResultMono);
@Override public Mono<ClientHttpResponse> connect(HttpMethod httpMethod, URI uri, Function<? super ClientHttpRequest, Mono<Void>> requestCallback) { MonoProcessor<ClientHttpResponse> result = MonoProcessor.create(); MockClientHttpRequest mockClientRequest = new MockClientHttpRequest(httpMethod, uri); MockServerHttpResponse mockServerResponse = new MockServerHttpResponse(); mockClientRequest.setWriteHandler(requestBody -> { log("Invoking HttpHandler for ", httpMethod, uri); ServerHttpRequest mockServerRequest = adaptRequest(mockClientRequest, requestBody); ServerHttpResponse responseToUse = prepareResponse(mockServerResponse, mockServerRequest); this.handler.handle(mockServerRequest, responseToUse).subscribe(aVoid -> {}, result::onError); return Mono.empty(); }); mockServerResponse.setWriteHandler(responseBody -> Mono.fromRunnable(() -> { log("Creating client response for ", httpMethod, uri); result.onNext(adaptResponse(mockServerResponse, responseBody)); })); log("Writing client request for ", httpMethod, uri); requestCallback.apply(mockClientRequest).subscribe(aVoid -> {}, result::onError); return result; }
@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"); }
@Test public void firstMonoJust() { MonoProcessor<Integer> mp = MonoProcessor.create(); StepVerifier.create(Mono.first(Mono.just(1), Mono.just(2)) .subscribeWith(mp)) .then(() -> assertThat(mp.isError()).isFalse()) .then(() -> assertThat(mp.isSuccess()).isTrue()) .then(() -> assertThat(mp.isTerminated()).isTrue()) .expectNext(1) .verifyComplete(); }
@Test public void scanProcessorSubscription() { MonoProcessor<String> test = MonoProcessor.create(); Subscription subscription = Operators.emptySubscription(); test.onSubscribe(subscription); assertThat(test.scan(Scannable.Attr.ACTUAL)).isNull(); assertThat(test.scan(Scannable.Attr.PARENT)).isSameAs(subscription); }
@Test public void subProtocol() throws Exception { String protocol = "echo-v1"; AtomicReference<HandshakeInfo> infoRef = new AtomicReference<>(); MonoProcessor<Object> output = MonoProcessor.create(); this.client.execute(getUrl("/sub-protocol"), new WebSocketHandler() { @Override public List<String> getSubProtocols() { return Collections.singletonList(protocol); } @Override public Mono<Void> handle(WebSocketSession session) { infoRef.set(session.getHandshakeInfo()); return session.receive() .map(WebSocketMessage::getPayloadAsText) .subscribeWith(output) .then(); } }) .block(TIMEOUT); HandshakeInfo info = infoRef.get(); assertThat(info.getHeaders().getFirst("Upgrade"), Matchers.equalToIgnoringCase("websocket")); assertEquals(protocol, info.getHeaders().getFirst("Sec-WebSocket-Protocol")); assertEquals("Wrong protocol accepted", protocol, info.getSubProtocol()); assertEquals("Wrong protocol detected on the server side", protocol, output.block(TIMEOUT)); }