/*
* Copyright 2009-2016 Weibo, Inc.
*
* 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.weibo.api.motan.protocol.yar;
import java.lang.reflect.Method;
import org.apache.commons.lang3.StringUtils;
import com.weibo.api.motan.exception.MotanBizException;
import com.weibo.api.motan.exception.MotanServiceException;
import com.weibo.api.motan.protocol.yar.annotation.YarConfig;
import com.weibo.api.motan.rpc.DefaultRequest;
import com.weibo.api.motan.rpc.DefaultResponse;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.rpc.Response;
import com.weibo.api.motan.rpc.URL;
import com.weibo.api.motan.util.ReflectUtil;
import com.weibo.yar.YarRequest;
import com.weibo.yar.YarResponse;
/**
*
* @Description yar protocol util.
* @author zhanglei
* @date 2016-6-8
*
*/
public class YarProtocolUtil {
public static String getYarPath(Class<?> interfaceClazz, URL url) {
if (interfaceClazz != null) {
YarConfig config = interfaceClazz.getAnnotation(YarConfig.class);
if (config != null && StringUtils.isNotBlank(config.path())) {
return config.path();
}
}
// '/group/urlpath' as default
return "/" + url.getGroup() + "/" + url.getPath();
}
/**
* convert yar request to motan rpc request
*
* @param yarRequest
* @param interfaceClass
* @return
*/
public static Request convert(YarRequest yarRequest, Class<?> interfaceClass) {
DefaultRequest request = new DefaultRequest();
request.setInterfaceName(interfaceClass.getName());
request.setMethodName(yarRequest.getMethodName());
request.setRequestId(yarRequest.getId());
addArguments(request, interfaceClass, yarRequest.getMethodName(), yarRequest.getParameters());
if (yarRequest instanceof AttachmentRequest) {
request.setAttachments(((AttachmentRequest) yarRequest).getAttachments());
}
return request;
}
public static YarRequest convert(Request request, String packagerName) {
YarRequest yarRequest = new YarRequest();
yarRequest.setId(request.getRequestId());
yarRequest.setMethodName(request.getMethodName());
yarRequest.setPackagerName(packagerName);
yarRequest.setParameters(request.getArguments());
return yarRequest;
}
public static Response convert(YarResponse yarResponse) {
DefaultResponse response = new DefaultResponse();
response.setRequestId(yarResponse.getId());
response.setValue(yarResponse.getRet());
if (StringUtils.isNotBlank(yarResponse.getError())) {
response.setException(new MotanBizException(yarResponse.getError()));
}
return response;
}
public static YarResponse convert(Response response, String packagerName) {
YarResponse yarResponse = new YarResponse();
yarResponse.setId(response.getRequestId());
yarResponse.setPackagerName(packagerName);
if (response.getException() != null) {
if (response.getException() instanceof MotanBizException) {
yarResponse.setError(response.getException().getCause().getMessage());
} else {
yarResponse.setError(response.getException().getMessage());
}
} else {
yarResponse.setRet(response.getValue());
}
return yarResponse;
}
/**
* add arguments
*
* @param interfaceClass
* @param methodName
* @param arguments
* @return
*/
private static void addArguments(DefaultRequest request, Class<?> interfaceClass, String methodName, Object[] arguments) {
Method targetMethod = null;
Method[] methods = interfaceClass.getDeclaredMethods();
for (Method m : methods) {
// FIXME parameters may be ambiguous in weak type language, temporarily by limiting the
// size of parameters with same method name to avoid.
if (m.getName().equalsIgnoreCase(methodName) && m.getParameterTypes().length == arguments.length) {
targetMethod = m;
break;
}
}
if (targetMethod == null) {
throw new MotanServiceException("cann't find request method. method name " + methodName);
}
request.setParamtersDesc(ReflectUtil.getMethodParamDesc(targetMethod));
if (arguments != null && arguments.length > 0) {
Class<?>[] argumentClazz = targetMethod.getParameterTypes();
request.setArguments(adaptParams(targetMethod, arguments, argumentClazz));
}
}
public static YarResponse buildDefaultErrorResponse(String errMsg, String packagerName) {
YarResponse yarResponse = new YarResponse();
yarResponse.setPackagerName(packagerName);
yarResponse.setError(errMsg);
yarResponse.setStatus("500");
return yarResponse;
}
// adapt parameters to java class type
private static Object[] adaptParams(Method method, Object[] arguments, Class<?>[] argumentClazz) {
// FIXME the real parameter type may not same with formal parameter, for instance, formal
// parameter type is int, the real parameter maybe use String in php
// any elegant way?
for (int i = 0; i < argumentClazz.length; i++) {
try {
if ("int".equals(argumentClazz[i].getName()) || "java.lang.Integer".equals(argumentClazz[i].getName())) {
if (arguments[i] == null) {
arguments[i] = 0;// default
} else if (arguments[i] instanceof String) {
arguments[i] = Integer.parseInt((String) arguments[i]);
} else if (arguments[i] instanceof Number) {
arguments[i] = ((Number) arguments[i]).intValue();
} else {
throw new RuntimeException();
}
} else if ("long".equals(argumentClazz[i].getName()) || "java.lang.Long".equals(argumentClazz[i].getName())) {
if (arguments[i] == null) {
arguments[i] = 0;// default
} else if (arguments[i] instanceof String) {
arguments[i] = Long.parseLong((String) arguments[i]);
} else if (arguments[i] instanceof Number) {
arguments[i] = ((Number) arguments[i]).longValue();
} else {
throw new RuntimeException();
}
} else if ("float".equals(argumentClazz[i].getName()) || "java.lang.Float".equals(argumentClazz[i].getName())) {
if (arguments[i] == null) {
arguments[i] = 0.0f;// default
} else if (arguments[i] instanceof String) {
arguments[i] = Float.parseFloat((String) arguments[i]);
} else if (arguments[i] instanceof Number) {
arguments[i] = ((Number) arguments[i]).floatValue();
} else {
throw new RuntimeException();
}
} else if ("double".equals(argumentClazz[i].getName()) || "java.lang.Double".equals(argumentClazz[i].getName())) {
if (arguments[i] == null) {
arguments[i] = 0.0f;// default
} else if (arguments[i] instanceof String) {
arguments[i] = Double.parseDouble((String) arguments[i]);
} else if (arguments[i] instanceof Number) {
arguments[i] = ((Number) arguments[i]).doubleValue();
} else {
throw new RuntimeException();
}
} else if ("boolean".equals(argumentClazz[i].getName()) || "java.lang.Boolean".equals(argumentClazz[i].getName())) {
if (arguments[i] instanceof Boolean) {
continue;
}
if (arguments[i] instanceof String) {
arguments[i] = Boolean.valueOf(((String) arguments[i]));
} else {
throw new RuntimeException();
}
}
} catch (Exception e) {
throw new MotanServiceException("adapt param fail! method:" + method.toString() + ", require param:"
+ argumentClazz[i].getName() + ", actual param:"
+ (arguments[i] == null ? null : arguments[i].getClass().getName() + "-" + arguments[i]));
}
}
return arguments;
}
}