/* * Copyright (C) 2012~2014 dinstone<dinstone@163.com> * * 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.dinstone.rpc.service; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.dinstone.rpc.RpcException; import com.dinstone.rpc.protocol.Result; import com.dinstone.rpc.protocol.RpcRequest; import com.dinstone.rpc.protocol.RpcResponse; /** * @author guojinfei * @version 1.0.0.2014-7-29 */ public class DefaultServiceHandler implements ServiceHandler, ServiceStats { private static final Logger LOG = LoggerFactory.getLogger(DefaultServiceHandler.class); private Map<Class<?>, Object> interfaceMap = new ConcurrentHashMap<Class<?>, Object>(); private Map<String, Service> serviceMap = new ConcurrentHashMap<String, Service>(); public DefaultServiceHandler() { regist(ServiceStats.class, this); } /** * {@inheritDoc} * * @see com.dinstone.rpc.service.ServiceHandler#regist(java.lang.Class, * java.lang.Object) */ public synchronized <T> void regist(Class<T> serviceInterface, T serviceObject) { if (!serviceInterface.isInstance(serviceObject)) { String message = "the specified service object[" + serviceObject.getClass() + "] is not assignment-compatible with the object represented by this Class[" + serviceInterface + "]."; LOG.warn(message); throw new RpcException(501, message); } Object obj = interfaceMap.get(serviceInterface); if (obj != null) { throw new RpcException(502, "multiple object registed with the service interface " + serviceInterface); } else { interfaceMap.put(serviceInterface, serviceObject); } String classPrefix = serviceInterface.getName() + "."; Map<String, Service> tmpMap = new HashMap<String, Service>(); Method[] methods = serviceInterface.getDeclaredMethods(); for (Method method : methods) { Service service = new Service(serviceObject, method); String key = classPrefix + method.getName(); if (tmpMap.containsKey(key)) { throw new RpcException(503, "method overloading is not supported"); } tmpMap.put(key, service); } serviceMap.putAll(tmpMap); } /** * {@inheritDoc} * * @see com.dinstone.rpc.service.ServiceHandler#handle(com.dinstone.rpc.protocol.RpcRequest) */ public RpcResponse handle(RpcRequest request) { Result result = null; try { Service service = find(request.getMethod()); if (service == null) { result = new Result(505, "no serivce"); } else { Object resObj = service.call(request.getParams()); result = new Result(200, resObj); } } catch (IllegalArgumentException e) { result = new Result(600, e.getMessage(), e); } catch (IllegalAccessException e) { result = new Result(601, e.getMessage(), e); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); result = new Result(500, t.getMessage(), t); } catch (Exception e) { result = new Result(509, "unkown exception", e); } return new RpcResponse(request.getMessageId(), request.getSerializeType(), result); } /** * {@inheritDoc} * * @see com.dinstone.rpc.service.ServiceStats#serviceList() */ public List<String> serviceList() { List<String> services = new ArrayList<String>(serviceMap.size()); for (Service service : serviceMap.values()) { services.add(description(service)); } return services; } private Service find(String methodName) { return serviceMap.get(methodName); } private String description(Service service) { Method method = service.getMethod(); StringBuilder desc = new StringBuilder(); desc.append(getTypeName(method.getReturnType()) + " "); desc.append(getTypeName(method.getDeclaringClass()) + "."); desc.append(method.getName() + "("); Class<?>[] params = method.getParameterTypes(); for (int j = 0; j < params.length; j++) { desc.append(getTypeName(params[j])); if (j < (params.length - 1)) { desc.append(","); } } desc.append(")"); return desc.toString(); } private static String getTypeName(Class<?> type) { if (type.isArray()) { try { Class<?> cl = type; int dimensions = 0; while (cl.isArray()) { dimensions++; cl = cl.getComponentType(); } StringBuilder sb = new StringBuilder(); sb.append(cl.getName()); for (int i = 0; i < dimensions; i++) { sb.append("[]"); } return sb.toString(); } catch (Throwable e) { } } return type.getName(); } }