package dgm.streaming.requestmapper;
import com.google.common.base.Optional;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Ernst Bunders
*/
public final class HttpRequestMapper {
private final List<HttpRequestMapping> requestMappings = new ArrayList<HttpRequestMapping>();
private static final Logger LOGGER = LoggerFactory.getLogger(HttpRequestMapper.class);
public HttpRequestMapper addMapping(RequestHandler requestHandler, HttpMethod... methods) {
requestMappings.add(new HttpRequestMapping(Arrays.asList(methods), requestHandler));
return this;
}
public void handleRequest(HttpRequest httpRequest, Channel channel) throws RequestHandlerException {
Optional<RequestHandler> handlerOption = selectHandler(httpRequest);
if (handlerOption.isPresent()) {
handlerOption.get().handleRequest(httpRequest, channel);
} else {
LOGGER.error("No request handler found for request: " + httpRequest);
}
}
private Optional<RequestHandler> selectHandler(final HttpRequest httpRequest) {
List<RequestHandler> possibleHandlers = new ArrayList<RequestHandler>();
for (HttpRequestMapping mapping : requestMappings) {
if (mapping.methods.contains(httpRequest.getMethod()) && mapping.pathMatcher.reset(httpRequest.getUri()).find()) {
possibleHandlers.add(mapping.handler);
}
}
switch (possibleHandlers.size()) {
case 0:
return Optional.absent();
case 1:
return Optional.of(possibleHandlers.get(0));
default:
throw new IllegalStateException("More than one possible handler was found for request query string: " + httpRequest.getUri());
}
}
private static final class HttpRequestMapping {
final List<HttpMethod> methods;
final Matcher pathMatcher;
final RequestHandler handler;
private HttpRequestMapping(List<HttpMethod> methods, RequestHandler handler) {
this.methods = methods;
this.handler = handler;
Pattern pattern = Pattern.compile(handler.getPathMatchingExpression());
pathMatcher = pattern.matcher("").reset(); /* just create the matcher for reuse: should this be thread safe???*/
}
}
public interface RequestHandler
{
void handleRequest(HttpRequest request, Channel channel) throws RequestHandlerException;
/**
* Returns the regular expression string that will be used to match the request path with.
*/
String getPathMatchingExpression();
}
}