/* * Copyright 1999-2011 Alibaba Group. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.rpc.protocol.hessian; 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 com.alibaba.dubbo.common.Constants; 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.caucho.hessian.HessianException; import com.caucho.hessian.client.HessianConnectionException; import com.caucho.hessian.client.HessianProxyFactory; import com.caucho.hessian.io.HessianMethodSerializationException; import com.caucho.hessian.server.HessianSkeleton; /** * http rpc support. * * @author qianlei */ public class HessianProtocol extends AbstractProxyProtocol { private final Map<String, HttpServer> serverMap = new ConcurrentHashMap<String, HttpServer>(); private final Map<String, HessianSkeleton> skeletonMap = new ConcurrentHashMap<String, HessianSkeleton>(); private HttpBinder httpBinder; public HessianProtocol() { super(HessianException.class); } public void setHttpBinder(HttpBinder httpBinder) { this.httpBinder = httpBinder; } public int getDefaultPort() { return 80; } private class HessianHandler implements HttpHandler { public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String uri = request.getRequestURI(); HessianSkeleton skeleton = skeletonMap.get(uri); if (! request.getMethod().equalsIgnoreCase("POST")) { response.setStatus(500); } else { RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); try { skeleton.invoke(request.getInputStream(), response.getOutputStream()); } catch (Throwable e) { throw new ServletException(e); } } } } 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 HessianHandler()); serverMap.put(addr, server); } final String path = url.getAbsolutePath(); HessianSkeleton skeleton = new HessianSkeleton(impl, type); skeletonMap.put(path, skeleton); return new Runnable() { public void run() { skeletonMap.remove(path); } }; } @SuppressWarnings("unchecked") protected <T> T doRefer(Class<T> serviceType, URL url) throws RpcException { HessianProxyFactory hessianProxyFactory = new HessianProxyFactory(); String client = url.getParameter(Constants.CLIENT_KEY, Constants.DEFAULT_HTTP_CLIENT); if ("httpclient".equals(client)) { hessianProxyFactory.setConnectionFactory(new HttpClientConnectionFactory()); } else if (client != null && client.length() > 0 && ! Constants.DEFAULT_HTTP_CLIENT.equals(client)) { throw new IllegalStateException("Unsupported http protocol client=\"" + client + "\"!"); } int timeout = url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); hessianProxyFactory.setConnectTimeout(timeout); hessianProxyFactory.setReadTimeout(timeout); return (T) hessianProxyFactory.create(serviceType, url.setProtocol("http").toJavaURL(), Thread.currentThread().getContextClassLoader()); } protected int getErrorCode(Throwable e) { if (e instanceof HessianConnectionException) { if (e.getCause() != null) { Class<?> cls = e.getCause().getClass(); if (SocketTimeoutException.class.equals(cls)) { return RpcException.TIMEOUT_EXCEPTION; } } return RpcException.NETWORK_EXCEPTION; } else if (e instanceof HessianMethodSerializationException) { return RpcException.SERIALIZATION_EXCEPTION; } return super.getErrorCode(e); } public void destroy() { super.destroy(); for (String key : new ArrayList<String>(serverMap.keySet())) { HttpServer server = serverMap.remove(key); if (server != null) { try { if (logger.isInfoEnabled()) { logger.info("Close hessian server " + server.getUrl()); } server.close(); } catch (Throwable t) { logger.warn(t.getMessage(), t); } } } } }