Add simple URL mapping and handling

This commit adds support for simple URL handler mapping (exact path
match) and an adapter for the HttpHandler interface to be used to
handle the request.

The SimpleUrlHandlerMappingIntegrationTests then maps the URLs
"/foo" and "/bar" to two different handlers.
This commit is contained in:
Rossen Stoyanchev
2015-08-24 17:30:50 -04:00
parent d6fd274771
commit bc7a5acd50
16 changed files with 301 additions and 65 deletions
@@ -19,21 +19,19 @@ import java.util.ArrayList;
import java.util.List;
import org.reactivestreams.Publisher;
import reactor.core.reactivestreams.PublisherFactory;
import reactor.core.reactivestreams.SubscriberWithContext;
import reactor.rx.Streams;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.reactive.web.http.ServerHttpHandler;
import org.springframework.reactive.web.http.HttpHandler;
import org.springframework.reactive.web.http.ServerHttpRequest;
import org.springframework.reactive.web.http.ServerHttpResponse;
/**
* @author Rossen Stoyanchev
*/
public class DispatcherHandler implements ServerHttpHandler {
public class DispatcherHandler implements HttpHandler {
private List<HandlerMapping> handlerMappings;
@@ -62,7 +60,7 @@ public class DispatcherHandler implements ServerHttpHandler {
if (handler == null) {
// No exception handling mechanism yet
response.setStatusCode(HttpStatus.NOT_FOUND);
return PublisherFactory.forEach(SubscriberWithContext::onComplete);
return Streams.empty();
}
HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
@@ -0,0 +1,53 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.reactive.web.dispatch.handler;
import org.reactivestreams.Publisher;
import reactor.rx.Streams;
import org.springframework.reactive.web.dispatch.HandlerAdapter;
import org.springframework.reactive.web.dispatch.HandlerResult;
import org.springframework.reactive.web.http.HttpHandler;
import org.springframework.reactive.web.http.ServerHttpRequest;
import org.springframework.reactive.web.http.ServerHttpResponse;
/**
* Support use of {@link HttpHandler} with
* {@link org.springframework.reactive.web.dispatch.DispatcherHandler
* DispatcherHandler} (which implements the same contract).
* The use of {@code DispatcherHandler} this way enables routing requests to
* one of many {@code HttpHandler} instances depending on the configured
* handler mappings.
*
* @author Rossen Stoyanchev
*/
public class HttpHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return HttpHandler.class.isAssignableFrom(handler.getClass());
}
@Override
public Publisher<HandlerResult> handle(ServerHttpRequest request, ServerHttpResponse response, Object handler) {
HttpHandler httpHandler = (HttpHandler) handler;
Publisher<Void> publisher = httpHandler.handle(request, response);
return Streams.wrap(publisher).map(aVoid -> null);
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.reactive.web.dispatch.handler;
import java.util.HashMap;
import java.util.Map;
import org.springframework.reactive.web.dispatch.HandlerMapping;
import org.springframework.reactive.web.http.ServerHttpRequest;
/**
* @author Rossen Stoyanchev
*/
public class SimpleUrlHandlerMapping implements HandlerMapping {
private final Map<String, Object> handlerMap = new HashMap<>();
public void setHandlers(Map<String, Object> handlers) {
this.handlerMap.clear();
if (handlers != null) {
this.handlerMap.putAll(handlers);
}
}
@Override
public Object getHandler(ServerHttpRequest request) {
return this.handlerMap.get(request.getURI().getPath());
}
}
@@ -18,14 +18,12 @@ package org.springframework.reactive.web.http;
import org.reactivestreams.Publisher;
import org.springframework.reactive.web.http.ServerHttpRequest;
import org.springframework.reactive.web.http.ServerHttpResponse;
/**
* @author Arjen Poutsma
* @author Rossen Stoyanchev
*/
public interface ServerHttpHandler {
public interface HttpHandler {
Publisher<Void> handle(ServerHttpRequest request, ServerHttpResponse response);
@@ -15,10 +15,7 @@
*/
package org.springframework.reactive.web.http;
import java.net.URI;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
/**
* @author Rossen Stoyanchev
@@ -23,7 +23,7 @@ import org.reactivestreams.Publisher;
import rx.Observable;
import rx.RxReactiveStreams;
import org.springframework.reactive.web.http.ServerHttpHandler;
import org.springframework.reactive.web.http.HttpHandler;
import org.springframework.util.Assert;
/**
@@ -31,10 +31,10 @@ import org.springframework.util.Assert;
*/
public class RequestHandlerAdapter implements RequestHandler<ByteBuf, ByteBuf> {
private final ServerHttpHandler httpHandler;
private final HttpHandler httpHandler;
public RequestHandlerAdapter(ServerHttpHandler httpHandler) {
public RequestHandlerAdapter(HttpHandler httpHandler) {
Assert.notNull(httpHandler, "'httpHandler' is required.");
this.httpHandler = httpHandler;
}
@@ -29,7 +29,7 @@ import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.reactive.web.http.ServerHttpHandler;
import org.springframework.reactive.web.http.HttpHandler;
/**
* @author Arjen Poutsma
@@ -43,10 +43,10 @@ public class HttpHandlerServlet extends HttpServlet {
private static Log logger = LogFactory.getLog(HttpHandlerServlet.class);
private ServerHttpHandler handler;
private HttpHandler handler;
public void setHandler(ServerHttpHandler handler) {
public void setHandler(HttpHandler handler) {
this.handler = handler;
}
@@ -55,7 +55,6 @@ public class RequestBodyPublisher implements ReadListener, Publisher<byte[]> {
@Override
public void subscribe(Subscriber<? super byte[]> s) {
this.subscriber = s;
this.subscriber.onSubscribe(new RequestBodySubscription());
}
@@ -99,13 +98,17 @@ public class RequestBodyPublisher implements ReadListener, Publisher<byte[]> {
public void onAllDataRead() throws IOException {
logger.debug("All data read");
this.synchronizer.readComplete();
this.subscriber.onComplete();
if (this.subscriber != null) {
this.subscriber.onComplete();
}
}
@Override
public void onError(Throwable t) {
logger.error("RequestBodyPublisher Error", t);
this.subscriber.onError(t);
if (this.subscriber != null) {
this.subscriber.onError(t);
}
}
private class RequestBodySubscription implements Subscription {
@@ -20,7 +20,6 @@ import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.reactivestreams.Publisher;