| package com.qianmi.dubbo.rpc.protocol.jsonrpc; |
| |
| import java.io.IOException; |
| import java.net.SocketTimeoutException; |
| import java.util.ArrayList; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.springframework.remoting.RemoteAccessException; |
| |
| import com.alibaba.dubbo.common.URL; |
| import com.alibaba.dubbo.remoting.http.HttpBinder; |
| import com.alibaba.dubbo.remoting.http.HttpHandler; |
| import com.alibaba.dubbo.remoting.http.HttpServer; |
| import com.alibaba.dubbo.rpc.RpcContext; |
| import com.alibaba.dubbo.rpc.RpcException; |
| import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol; |
| import com.googlecode.jsonrpc4j.HttpException; |
| import com.googlecode.jsonrpc4j.JsonRpcClientException; |
| import com.googlecode.jsonrpc4j.JsonRpcServer; |
| import com.googlecode.jsonrpc4j.spring.JsonProxyFactoryBean; |
| |
| /** |
| * Created by wuwen on 15/4/1. |
| */ |
| public class JsonRpcProtocol extends AbstractProxyProtocol { |
| |
| public static final String ACCESS_CONTROL_ALLOW_ORIGIN_HEADER = "Access-Control-Allow-Origin"; |
| public static final String ACCESS_CONTROL_ALLOW_METHODS_HEADER = "Access-Control-Allow-Methods"; |
| public static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers"; |
| |
| private final Map<String, HttpServer> serverMap = new ConcurrentHashMap<>(); |
| |
| private final Map<String, JsonRpcServer> skeletonMap = new ConcurrentHashMap<>(); |
| |
| private HttpBinder httpBinder; |
| |
| public JsonRpcProtocol() { |
| super(HttpException.class, JsonRpcClientException.class); |
| } |
| |
| public void setHttpBinder(HttpBinder httpBinder) { |
| this.httpBinder = httpBinder; |
| } |
| |
| public int getDefaultPort() { |
| return 80; |
| } |
| |
| private class InternalHandler implements HttpHandler { |
| |
| private boolean cors; |
| |
| public InternalHandler(boolean cors) { |
| this.cors = cors; |
| } |
| |
| public void handle(HttpServletRequest request, HttpServletResponse response) |
| throws IOException, ServletException { |
| String uri = request.getRequestURI(); |
| JsonRpcServer skeleton = skeletonMap.get(uri); |
| if (cors) { |
| response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*"); |
| response.setHeader(ACCESS_CONTROL_ALLOW_METHODS_HEADER, "POST"); |
| response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS_HEADER, "*"); |
| } |
| if (request.getMethod().equalsIgnoreCase("OPTIONS")) { |
| response.setStatus(200); |
| } else if (request.getMethod().equalsIgnoreCase("POST")) { |
| |
| RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); |
| try { |
| skeleton.handle(request.getInputStream(), response.getOutputStream()); |
| } catch (Throwable e) { |
| throw new ServletException(e); |
| } |
| } else { |
| response.setStatus(500); |
| } |
| } |
| |
| } |
| |
| protected <T> Runnable doExport(T impl, Class<T> type, URL url) throws RpcException { |
| String addr = url.getIp() + ":" + url.getPort(); |
| HttpServer server = serverMap.get(addr); |
| if (server == null) { |
| server = httpBinder.bind(url, new InternalHandler(url.getParameter("cors", false))); |
| serverMap.put(addr, server); |
| } |
| final String path = url.getAbsolutePath(); |
| JsonRpcServer skeleton = new JsonRpcServer(impl, type); |
| skeletonMap.put(path, skeleton); |
| return new Runnable() { |
| public void run() { |
| skeletonMap.remove(path); |
| } |
| }; |
| } |
| |
| @SuppressWarnings("unchecked") |
| protected <T> T doRefer(final Class<T> serviceType, URL url) throws RpcException { |
| JsonProxyFactoryBean jsonProxyFactoryBean = new JsonProxyFactoryBean(); |
| jsonProxyFactoryBean.setServiceUrl(url.setProtocol("http").toIdentityString()); |
| jsonProxyFactoryBean.setServiceInterface(serviceType); |
| |
| jsonProxyFactoryBean.afterPropertiesSet(); |
| return (T) jsonProxyFactoryBean.getObject(); |
| } |
| |
| protected int getErrorCode(Throwable e) { |
| if (e instanceof RemoteAccessException) { |
| e = e.getCause(); |
| } |
| if (e != null) { |
| Class<?> cls = e.getClass(); |
| if (SocketTimeoutException.class.equals(cls)) { |
| return RpcException.TIMEOUT_EXCEPTION; |
| } else if (IOException.class.isAssignableFrom(cls)) { |
| return RpcException.NETWORK_EXCEPTION; |
| } else if (ClassNotFoundException.class.isAssignableFrom(cls)) { |
| return RpcException.SERIALIZATION_EXCEPTION; |
| } |
| } |
| return super.getErrorCode(e); |
| } |
| |
| public void destroy() { |
| super.destroy(); |
| for (String key : new ArrayList<>(serverMap.keySet())) { |
| HttpServer server = serverMap.remove(key); |
| if (server != null) { |
| try { |
| if (logger.isInfoEnabled()) { |
| logger.info("Close jsonrpc server " + server.getUrl()); |
| } |
| server.close(); |
| } catch (Throwable t) { |
| logger.warn(t.getMessage(), t); |
| } |
| } |
| } |
| } |
| |
| } |