package com.nabalive.framework.web;
import com.nabalive.framework.web.exception.HttpException;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferOutputStream;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.*;
import org.jboss.netty.handler.codec.http.*;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import org.jboss.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.PrintWriter;
import java.nio.channels.ClosedChannelException;
import java.util.Map;
import java.util.UUID;
import org.jboss.netty.handler.codec.http.HttpHeaders;
/**
* Created by IntelliJ IDEA.
* User: Julien Cheype
* Date: 5/5/11
*/
public class HttpApiServerHandler extends IdleStateAwareChannelHandler {
private static final Logger logger = LoggerFactory.getLogger(HttpApiServerHandler.class);
private RestHandler restHandler;
public HttpApiServerHandler(RestHandler restHandler) {
this.restHandler = restHandler;
}
private void execBeforeFilters(Request request, Response response) throws Exception {
String path = request.qs.getPath();
for (Route route : restHandler.getRouteList(RestHandler.beforeFilter)) {
final Map<String, String> map = route.parse(path, request.request.getHeader("Content-Type"));
if (map != null) {
route.handle(request, response, map);
}
}
}
private void execAfterFilters(Request request, Response response) throws Exception {
String path = request.qs.getPath();
for (Route route : restHandler.getRouteList(RestHandler.afterFilter)) {
final Map<String, String> map = route.parse(path, request.request.getHeader("Content-Type"));
if (map != null) {
route.handle(request, response, map);
}
}
}
private void execHttpMethod(Request request, Response response) throws Exception {
String path = request.qs.getPath();
for (Route route : restHandler.getRouteList(request.request.getMethod())) {
final Map<String, String> map = route.parse(path, request.request.getHeader("Content-Type"));
if (map != null) {
route.handle(request, response, map);
return;
}
}
throw new HttpException(HttpResponseStatus.NOT_FOUND);
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) {
HttpRequest httpRequest = (HttpRequest) event.getMessage();
logger.debug("Request: {}", httpRequest);
QueryStringDecoder qs = new QueryStringDecoder(httpRequest.getUri());
final Request request = new Request(ctx, httpRequest, qs);
final Response response = new Response(ctx, httpRequest);
try {
execBeforeFilters(request, response);
execHttpMethod(request, response);
execAfterFilters(request, response);
} catch (HttpException e) {
HttpResponse httpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, e.getStatus());
ctx.getChannel().write(httpResponse).addListener(ChannelFutureListener.CLOSE);
} catch (Exception e) {
HttpResponse httpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
if (logger.isDebugEnabled()) {
ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();
PrintWriter printWriter = new PrintWriter(new ChannelBufferOutputStream(channelBuffer));
e.printStackTrace(printWriter);
printWriter.close();
httpResponse.setContent(channelBuffer);
}
logger.error("web server error: ", e);
ctx.getChannel().write(httpResponse).addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
if(e.getCause() instanceof ClosedChannelException){
return;
}
String errorid = UUID.randomUUID().toString();
logger.error("ERROR HTTP: {}\n", errorid, e.getCause());
HttpResponse httpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
httpResponse.setHeader("id", errorid);
if (logger.isDebugEnabled()) {
ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();
PrintWriter printWriter = new PrintWriter(new ChannelBufferOutputStream(channelBuffer));
e.getCause().printStackTrace(printWriter);
printWriter.close();
httpResponse.setContent(channelBuffer);
}
ctx.getChannel().write(httpResponse).addListener(ChannelFutureListener.CLOSE);
Channel ch = e.getChannel();
ch.close();
}
@Override
public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
e.getChannel().close();
}
public void setRestHandler(RestHandler restHandler) {
this.restHandler = restHandler;
}
}