/** * Dianping.com Inc. * Copyright (c) 2003-2013 All Rights Reserved. */ package com.dianping.pigeon.remoting.provider.service.method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.dianping.pigeon.remoting.common.exception.BadRequestException; import com.dianping.pigeon.remoting.common.util.Constants; import com.dianping.pigeon.remoting.provider.exception.InvocationFailureException; import com.dianping.pigeon.util.ClassUtils; public class ServiceMethodCache { /** * 根据方法名和参数个数Map方法集合 */ private Map<String, Map<Integer, List<ServiceMethod>>> methods = new ConcurrentHashMap<String, Map<Integer, List<ServiceMethod>>>(); private Map<String, Map<ServiceParam, ServiceMethod>> bestMacthMethod = new ConcurrentHashMap<String, Map<ServiceParam, ServiceMethod>>(); private ServiceMethod currentMethod; private int methodSize = 0; private Object service; // private String serviceName; public ServiceMethodCache(String serviceName, Object service) { // this.serviceName = serviceName; this.service = service; } public ServiceMethod getCurrentMethod() { return currentMethod; } void addMethod(String methodName, ServiceMethod method) { if (this.currentMethod == null) { this.currentMethod = method; } Map<Integer, List<ServiceMethod>> methodMap = this.methods.get(methodName); if (methodMap == null) { methodMap = new HashMap<Integer, List<ServiceMethod>>(); this.methods.put(methodName, methodMap); } List<ServiceMethod> methodList = methodMap.get(method.getParameterSize()); if (methodList == null) { methodList = new ArrayList<ServiceMethod>(); methodMap.put(method.getParameterSize(), methodList); } methodList.add(method); methodSize++; } public ServiceMethod getMethod(String methodName, ServiceParam paramNames) throws InvocationFailureException { if (methodSize == 1) { return this.currentMethod; } else { ServiceMethod method = getBestMatchMethodForCache(methodName, paramNames); if (method == null) { synchronized (this) { method = getBestMatchMethodForCache(methodName, paramNames); if (method == null) { method = getBestMatchMethod(methodName, paramNames); this.bestMacthMethod.get(methodName).put(paramNames, method); } } } return method; } } private ServiceMethod getBestMatchMethodForCache(String methodName, ServiceParam paramNames) { Map<ServiceParam, ServiceMethod> paramMethodMap = this.bestMacthMethod.get(methodName); if (paramMethodMap == null) { paramMethodMap = new HashMap<ServiceParam, ServiceMethod>(); this.bestMacthMethod.put(methodName, paramMethodMap); } return paramMethodMap.get(paramNames); } private ServiceMethod getBestMatchMethod(String methodName, ServiceParam paramNames) throws InvocationFailureException { Map<Integer, List<ServiceMethod>> methodMap = this.methods.get(methodName); if (methodMap == null) { throw new BadRequestException("the service " + this.service + " is not matched with method:" + methodName); } List<ServiceMethod> methodList = methodMap.get(paramNames.getLength()); if (methodList == null || methodList.size() == 0) { throw new BadRequestException("the service " + this.service + " is not matched with method:" + methodName + " for " + paramNames.getLength() + " parameters"); } if (paramNames.getLength() == 0) { return methodList.get(0); } int matchingValue = -1; ServiceMethod bestMethod = null; for (ServiceMethod m : methodList) { int mv = matching(m, paramNames.getParamNames(), false); if (mv > matchingValue) { matchingValue = mv; bestMethod = m; } } if (matchingValue < 0) { for (ServiceMethod m : methodList) { int mv = matching(m, paramNames.getParamNames(), true); if (mv > matchingValue) { matchingValue = mv; bestMethod = m; } } if (matchingValue >= 0) { bestMethod.setNeedCastParameterClasses(true); } } if (matchingValue < 0) { throw new BadRequestException("the service " + this.service + " is not matched with method:" + methodName + " for parameter class types"); } return bestMethod; } /** * * 返回匹配度 如果返回值等于参数个数,表示完全匹配 如果返回值为0---参数个数,表示部分匹配 如果返回-1,表示有不匹配项 * * @param paramClassNames * @return * @throws InvocationFailureException */ private int matching(ServiceMethod method, String[] paramClassNames, boolean cast) throws InvocationFailureException { int k = 0; for (int i = 0; i < paramClassNames.length; i++) { if (paramClassNames[i].equals(Constants.TRANSFER_NULL)) { continue; } Class<?> paramClass = null; try { paramClass = ClassUtils.loadClass(paramClassNames[i]); } catch (ClassNotFoundException e) { throw new BadRequestException("no class found for parameter:" + paramClassNames[i]); } if (paramClass == method.getParameterClasses()[i]) { k++; } else if (cast) { if (paramClassNames[i].equals(Double.class.getName())) { paramClass = Float.class; } else if (paramClassNames[i].equals(Integer.class.getName())) { paramClass = Short.class; } if (paramClass == method.getParameterClasses()[i]) { k++; } } if (!method.getParameterClasses()[i].isAssignableFrom(paramClass)) { return -1; } } return k; } public Map<String, Map<Integer, List<ServiceMethod>>> getMethodMap() { return methods; } }