package netflix.karyon.transport.http;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.reactivex.netty.protocol.http.server.HttpServerRequest;
import io.reactivex.netty.protocol.http.server.HttpServerResponse;
import io.reactivex.netty.protocol.http.server.RequestHandler;
import netflix.karyon.transport.interceptor.InterceptorKey;
import rx.Observable;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A simple implementation for handling requests for different URIs. This router provides a facility to update the
* routes at runtime. Thread-safety is maintained by using a "copy-on-write" data structure underneath, hence it comes
* with an object allocation cost.
*
* The correct way to use this router would be to create all the routes at startup and then do not update the routes
* at runtime unless it is required.
*
* @author Nitesh Kant
*/
public class SimpleUriRouter<I, O> implements RequestHandler<I, O> {
private final CopyOnWriteArrayList<Route> routes;
public SimpleUriRouter() {
routes = new CopyOnWriteArrayList<Route>();
}
@Override
public Observable<Void> handle(HttpServerRequest<I> request, HttpServerResponse<O> response) {
HttpKeyEvaluationContext context = new HttpKeyEvaluationContext(response.getChannel());
for (Route route : routes) {
if (route.key.apply(request, context)) {
return route.getHandler().handle(request, response);
}
}
// None of the routes matched.
response.setStatus(HttpResponseStatus.NOT_FOUND);
return response.close();
}
/**
* Add a new URI -< Handler route to this router.
* @param uri URI to match.
* @param handler Request handler.
* @return The updated router.
*/
public SimpleUriRouter<I, O> addUri(String uri, RequestHandler<I, O> handler) {
routes.add(new Route(new ServletStyleUriConstraintKey<I>(uri, ""), handler));
return this;
}
/**
* Add a new URI regex -< Handler route to this router.
* @param uriRegEx URI regex to match
* @param handler Request handler.
* @return The updated router.
*/
public SimpleUriRouter<I, O> addUriRegex(String uriRegEx, RequestHandler<I, O> handler) {
routes.add(new Route(new RegexUriConstraintKey<I>(uriRegEx), handler));
return this;
}
private class Route {
private final InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key;
private final RequestHandler<I, O> handler;
public Route(InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> key,
RequestHandler<I, O> handler) {
this.key = key;
this.handler = handler;
}
public InterceptorKey<HttpServerRequest<I>, HttpKeyEvaluationContext> getKey() {
return key;
}
public RequestHandler<I, O> getHandler() {
return handler;
}
}
}