/**
*
*/
package jframe.pay.http.handler;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.InetSocketAddress;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.regex.Pattern;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.ReferenceCountUtil;
/**
* @author dzh
* @date Jul 25, 2014 9:04:17 AM
* @since 1.0
*/
@Sharable
public class HttpReqDispatcher extends SimpleChannelInboundHandler<HttpObject> {
private static final Logger LOG = LoggerFactory.getLogger(HttpReqDispatcher.class);
/**
* <id,Dispatcher>
*/
private List<Dispatcher> _dispatcher = new LinkedList<Dispatcher>();
/**
* <url,handler clazz>
*/
private Map<String, WeakReference<String>> _cache = new WeakHashMap<String, WeakReference<String>>();
static String FILE_DISPATCHER = "dispatcher.xml";
public HttpReqDispatcher() {
loadDispatcher(FILE_DISPATCHER, _dispatcher);
}
public void loadDispatcher(String file, List<Dispatcher> dispatcher) {
InputStream is = getClass().getResourceAsStream(file);
if (is == null) {
LOG.error("Not found dispatcher.xml");
return;
}
_dispatcher.clear();
SAXReader reader = new SAXReader();
try {
Document doc = reader.read(is);
Element root = doc.getRootElement();
String method = root.attributeValue("method", "POST");
@SuppressWarnings("unchecked")
List<Element> elements = root.elements("dispatcher");
Dispatcher d = null;
for (Element e : elements) {
d = new Dispatcher();
d.setId(e.attributeValue("id"));
d.setMethod(e.attributeValue("method", method));
d.setUrl(e.elementTextTrim("url-pattern"));
d.setClazz(e.elementTextTrim("handler"));
dispatcher.add(d);
}
} catch (DocumentException e) {
LOG.error(e.getMessage());
} finally {
try {
is.close();
reader.resetHandlers();
} catch (IOException e) {
LOG.error(e.getMessage());
}
}
}
/**
* request regular expression
*/
// public final static Pattern Req_Regx = Pattern
// .compile("\\/(.*?)\\/(.*?)(?:\\/(.*))?");
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if (msg instanceof HttpRequest) {
HttpRequest req = (HttpRequest) msg;
if (LOG.isDebugEnabled()) {
LOG.debug("Dispatch req path {} method {}", req.getUri(), req.getMethod().name());
}
// pay client req
final String reqUrl = req.getUri();
Map<String, WeakReference<String>> cache = _cache;
WeakReference<String> wr = cache.get(reqUrl);
String clazz = wr != null && wr.get() != null ? wr.get() : null;
if (clazz != null) {
// if (reqUrl.startsWith("/common/image/download")) {
// ctx.pipeline().addLast("http aggregator",
// new HttpObjectAggregator(65536));
// ctx.pipeline().addLast("http chunk",
// new ChunkedWriteHandler());
// }
ctx.pipeline().addLast((ChannelHandler) getClass().getClassLoader().loadClass(clazz).newInstance());
} else {
List<Dispatcher> list = _dispatcher;
boolean notFound = true;
for (Dispatcher d : list) {
if (d.getMethod().contains(req.getMethod().name()) && Pattern.matches(d.getUrl(), reqUrl)) {
// if (d.getId().equals("img.down")) {
// ctx.pipeline().remove("http compressor");
// ctx.pipeline().addLast("http aggregator",
// new HttpObjectAggregator(65536)); //
// ctx.pipeline().addLast("http chunk",
// new ChunkedWriteHandler());
// }
ctx.pipeline().addLast(
(ChannelHandler) getClass().getClassLoader().loadClass(d.getClazz()).newInstance());
cache.put(reqUrl, new WeakReference<String>(d.getClazz()));
notFound = false;
break;
}
}
if (notFound) {
// ctx.pipeline().addLast(VoidHandler);
// cache.put(reqUrl, new
// WeakReference<String>(VoidHandler.getClass().getName()));
// LOG.error("Not found reqUrl->{}", reqUrl);
throw new Exception("HttpReqDispatcher not match uri->" + reqUrl + " method->" + req.getMethod());
}
}
}
ReferenceCountUtil.retain(msg);
ctx.fireChannelRead(msg);
}
// static final VoidHandler VoidHandler = new VoidHandler();
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
String remoteIp = ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName();
if (LOG.isDebugEnabled()) {
LOG.error(cause.getMessage() + " " + remoteIp, cause);
} else {
LOG.error(cause.getMessage() + " ip->{}", remoteIp);
}
ctx.close();
}
}