001package com.facebook.swift.service;
002
003import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
004
005import java.util.Iterator;
006import java.util.ServiceLoader;
007
008import org.jboss.netty.buffer.ChannelBuffer;
009import org.jboss.netty.buffer.ChannelBuffers;
010import org.jboss.netty.channel.ChannelFutureListener;
011import org.jboss.netty.channel.ChannelHandlerContext;
012import org.jboss.netty.channel.MessageEvent;
013import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
014import org.jboss.netty.channel.UpstreamMessageEvent;
015import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
016import org.jboss.netty.handler.codec.http.HttpMethod;
017import org.jboss.netty.handler.codec.http.HttpRequest;
018import org.jboss.netty.handler.codec.http.HttpResponse;
019
020import com.facebook.nifty.core.ThriftMessage;
021import com.facebook.nifty.core.ThriftTransportType;
022import com.google.common.base.Supplier;
023import com.google.common.base.Throwables;
024import com.google.common.io.Resources;
025
026/**
027 * XHR(XML Http Request)解码器<br>
028 * 将{@link HttpRequest}请求的内容数据(content)转为{@link ThriftMessage},
029 * 提供给{@link com.facebook.nifty.core.NiftyDispatcher}
030 * @author guyadong
031 *
032 */
033public class ThriftXHRDecoder extends SimpleChannelUpstreamHandler implements Supplier<HttpRequest> {
034        
035        private HttpRequest request;
036        public ThriftXHRDecoder() {
037        }
038        private static volatile byte[] homepage;
039        /**
040         * SPI(Service Provider Interface)机制加载 {@link XHRHomepageProvider}实例获取页面数据,没有找到返回默认页面数据
041         * @return homepage页面数据
042         * @throws Exception 
043         */
044        private static byte[] loadHomepageByXHRHomepageProvider() throws Exception {            
045                ServiceLoader<XHRHomepageProvider> providers = ServiceLoader.load(XHRHomepageProvider.class);
046                Iterator<XHRHomepageProvider> itor = providers.iterator();
047                if(itor.hasNext()){
048                        XHRHomepageProvider provider = itor.next();
049                        try{
050                                byte [] homepage = provider.homepage();
051                                if(homepage != null){
052                                        return homepage;
053                                }
054                        } catch (Exception e) {
055                                // 读取异常时使用默认页面数据
056                        }
057                }
058                // 返回默认HOMEPAGE数据
059                return Resources.toByteArray(ThriftXHRDecoder.class.getResource("/xhr_homepage.html")); 
060        
061        }
062        private static byte[] loadHomepage(){
063                if(null == homepage){
064                        synchronized (ThriftXHRDecoder.class) {
065                                if(null == homepage){
066                                        try {
067                                                homepage = loadHomepageByXHRHomepageProvider();                                         
068                                        } catch (Exception e) {
069                                                Throwables.throwIfUnchecked(e);
070                                                throw new RuntimeException(e);
071                                        }
072                                }
073                        }
074                }
075                return homepage;
076        }
077        @Override
078        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
079                if(e.getMessage() instanceof HttpRequest){
080                        request = (HttpRequest)e.getMessage();
081                        if(request.getContent().readable()){
082                                if(HttpMethod.POST.equals(request.getMethod())){
083                                        ThriftMessage thriftMessage = new ThriftMessage(request.getContent(),ThriftTransportType.UNFRAMED);
084                                        ctx.sendUpstream(new UpstreamMessageEvent(ctx.getChannel(), thriftMessage, e.getRemoteAddress()));
085                                        return;
086                                }
087                        }else{
088                                // 空请求(没有内容)时输出首页
089                        HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), OK);
090                        ChannelBuffer content = ChannelBuffers.wrappedBuffer(loadHomepage());
091                        response.setContent(content);
092                        ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
093                                return ;
094                        }
095                }
096                super.messageReceived(ctx, e);
097        }
098        @Override
099        public HttpRequest get() {
100                return request;
101        }
102}