From d319edba28d0fbf24b58525bff3cc5bd04dc934f Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 24 Nov 2015 17:29:37 -0500 Subject: [PATCH] HandlerMapping is now asynchronous --- .../web/reactive/DispatcherHandler.java | 45 ++++++++++--------- .../web/reactive/HandlerMapping.java | 4 +- .../handler/SimpleUrlHandlerMapping.java | 9 +++- .../RequestMappingHandlerMapping.java | 9 ++-- .../RequestMappingHandlerMappingTests.java | 26 ++++++++--- 5 files changed, 59 insertions(+), 34 deletions(-) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java index 48a1b180b8..3070db7f27 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java @@ -98,41 +98,33 @@ public class DispatcherHandler implements ReactiveHttpHandler, ApplicationContex logger.debug("Processing " + request.getMethod() + " request for [" + request.getURI() + "]"); } - Object handler = getHandler(request); - if (handler == null) { + Publisher handlerPublisher = getHandler(request); + if (handlerPublisher == null) { // No exception handling mechanism yet response.setStatusCode(HttpStatus.NOT_FOUND); response.writeHeaders(); return Publishers.empty(); } - HandlerAdapter handlerAdapter = getHandlerAdapter(handler); - if (handlerAdapter == null) { - return Publishers.error(new IllegalStateException("No HandlerAdapter for " + handler)); - } - - Publisher resultPublisher = handlerAdapter.handle(request, response, handler); + Publisher resultPublisher = Publishers.concatMap(handlerPublisher, handler -> { + HandlerAdapter handlerAdapter = getHandlerAdapter(handler); + return handlerAdapter.handle(request, response, handler); + }); return Publishers.concatMap(resultPublisher, result -> { - for (HandlerResultHandler resultHandler : resultHandlers) { - if (resultHandler.supports(result)) { - return resultHandler.handleResult(request, response, result); - } - } - return Publishers.error(new IllegalStateException( - "No HandlerResultHandler for " + result.getValue())); + HandlerResultHandler handler = getResultHandler(result); + return handler.handleResult(request, response, result); }); } - protected Object getHandler(ReactiveServerHttpRequest request) { - Object handler = null; + protected Publisher getHandler(ReactiveServerHttpRequest request) { for (HandlerMapping handlerMapping : this.handlerMappings) { - handler = handlerMapping.getHandler(request); - if (handler != null) { - break; + Publisher handlerPublisher = handlerMapping.getHandler(request); + if (handlerPublisher != null) { + return handlerPublisher; } } - return handler; + return null; } protected HandlerAdapter getHandlerAdapter(Object handler) { @@ -141,7 +133,16 @@ public class DispatcherHandler implements ReactiveHttpHandler, ApplicationContex return handlerAdapter; } } - return null; + throw new IllegalStateException("No HandlerAdapter: " + handler); + } + + protected HandlerResultHandler getResultHandler(HandlerResult handlerResult) { + for (HandlerResultHandler resultHandler : resultHandlers) { + if (resultHandler.supports(handlerResult)) { + return resultHandler; + } + } + throw new IllegalStateException("No HandlerResultHandler: " + handlerResult.getValue()); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java index 89e11f6521..0fd4741666 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java @@ -16,6 +16,8 @@ package org.springframework.web.reactive; +import org.reactivestreams.Publisher; + import org.springframework.http.server.ReactiveServerHttpRequest; /** @@ -23,6 +25,6 @@ import org.springframework.http.server.ReactiveServerHttpRequest; */ public interface HandlerMapping { - Object getHandler(ReactiveServerHttpRequest request); + Publisher getHandler(ReactiveServerHttpRequest request); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java index 8e1c906dd2..1eac42a113 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java @@ -19,6 +19,9 @@ package org.springframework.web.reactive.handler; import java.util.HashMap; import java.util.Map; +import org.reactivestreams.Publisher; +import reactor.Publishers; + import org.springframework.http.server.ReactiveServerHttpRequest; import org.springframework.web.reactive.HandlerMapping; @@ -39,8 +42,10 @@ public class SimpleUrlHandlerMapping implements HandlerMapping { @Override - public Object getHandler(ReactiveServerHttpRequest request) { - return this.handlerMap.get(request.getURI().getPath()); + public Publisher getHandler(ReactiveServerHttpRequest request) { + String path = request.getURI().getPath(); + Object handler = this.handlerMap.get(path); + return (handler != null ? Publishers.just(handler) : null); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMapping.java index 8fa2c682be..ed9670b3e8 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMapping.java @@ -27,6 +27,8 @@ import java.util.TreeSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.reactivestreams.Publisher; +import reactor.Publishers; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; @@ -92,15 +94,16 @@ public class RequestMappingHandlerMapping implements HandlerMapping, } @Override - public Object getHandler(ReactiveServerHttpRequest request) { + public Publisher getHandler(ReactiveServerHttpRequest request) { for (Map.Entry entry : this.methodMap.entrySet()) { RequestMappingInfo info = entry.getKey(); if (info.matchesRequest(request)) { + HandlerMethod handlerMethod = entry.getValue(); if (logger.isDebugEnabled()) { logger.debug("Mapped " + request.getMethod() + " " + - request.getURI().getPath() + " to [" + entry.getValue() + "]"); + request.getURI().getPath() + " to [" + handlerMethod + "]"); } - return entry.getValue(); + return Publishers.just(handlerMethod); } } return null; diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMappingTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMappingTests.java index 93e7858989..5fda7eb163 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMappingTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/method/annotation/RequestMappingHandlerMappingTests.java @@ -19,10 +19,13 @@ package org.springframework.web.reactive.method.annotation; import java.net.URI; import java.net.URISyntaxException; import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.reactivestreams.Publisher; +import reactor.rx.Streams; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -34,6 +37,7 @@ import org.springframework.web.context.support.StaticWebApplicationContext; import org.springframework.web.method.HandlerMethod; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; /** * @author Sebastien Deleuze @@ -56,19 +60,29 @@ public class RequestMappingHandlerMappingTests { @Test public void path() throws Exception { ReactiveServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "boo"); - HandlerMethod handler = (HandlerMethod) this.mapping.getHandler(request); - assertEquals(TestController.class.getMethod("boo"), handler.getMethod()); + Publisher handlerPublisher = this.mapping.getHandler(request); + HandlerMethod handlerMethod = toHandlerMethod(handlerPublisher); + assertEquals(TestController.class.getMethod("boo"), handlerMethod.getMethod()); } @Test public void method() throws Exception { ReactiveServerHttpRequest request = new MockServerHttpRequest(HttpMethod.POST, "foo"); - HandlerMethod handler = (HandlerMethod) this.mapping.getHandler(request); - assertEquals(TestController.class.getMethod("postFoo"), handler.getMethod()); + Publisher handlerPublisher = this.mapping.getHandler(request); + HandlerMethod handlerMethod = toHandlerMethod(handlerPublisher); + assertEquals(TestController.class.getMethod("postFoo"), handlerMethod.getMethod()); request = new MockServerHttpRequest(HttpMethod.GET, "foo"); - handler = (HandlerMethod) this.mapping.getHandler(request); - assertEquals(TestController.class.getMethod("getFoo"), handler.getMethod()); + handlerPublisher = this.mapping.getHandler(request); + handlerMethod = toHandlerMethod(handlerPublisher); + assertEquals(TestController.class.getMethod("getFoo"), handlerMethod.getMethod()); + } + + private HandlerMethod toHandlerMethod(Publisher handlerPublisher) throws InterruptedException { + assertNotNull(handlerPublisher); + List handlerList = Streams.wrap(handlerPublisher).toList().await(5, TimeUnit.SECONDS); + assertEquals(1, handlerList.size()); + return (HandlerMethod) handlerList.get(0); }