/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public 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
*
* https://opensource.org/licenses/GPL-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 org.msec.rpc;
import api.log.msec.org.AccessLog;
import api.monitor.msec.org.AccessMonitor;
import com.google.protobuf.MessageLite;
import org.apache.log4j.Logger;
import org.jboss.netty.channel.ChannelHandlerContext;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
public class RequestProcessor implements Callable<RpcResponse> {
private static Logger log = Logger.getLogger(RequestProcessor.class.getName());
private RpcContext rpcContext;
private static ThreadLocal<Map<String, Object>> threadContext = new ThreadLocal<Map<String, Object>>();
public static void setThreadContext(String key, Object value) {
Map<String, Object> context = threadContext.get();
if (context == null) {
context = new HashMap<String, Object>();
threadContext.set(context);
}
context.put(key, value);
}
public static Object getThreadContext(String key) {
Map<String, Object> context = threadContext.get();
if (context == null) {
return null;
}
return context.get(key);
}
public static void clearThreadContext() {
Map<String, Object> context = threadContext.get();
if (context != null) {
context.clear();
}
threadContext.remove();
}
public RequestProcessor(ChannelHandlerContext ctx, RpcRequest request) {
rpcContext = new RpcContext(request, ctx);
}
public void processListCgi(RpcRequest rpcRequest, RpcResponse rpcResponse) {
StringBuilder sb = new StringBuilder();
Map<String, Map<String, List<ServiceFactory.ServiceMethodEntry>>> serviceMethodMap = ServiceFactory.getServiceMethodMap();
List<String> serviceMethodList = new ArrayList<String>();
sb.append("<html><head><title>MSEC SRPC TEST</title></head>\n<body>\n");
sb.append("<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-latest.js\"></script>\n");
for (String serviceName : serviceMethodMap.keySet()) {
sb.append("\t<h1>" + serviceName + "</h1><br><br> \n");
for (String methodName : serviceMethodMap.get(serviceName).keySet()) {
sb.append("\t<h2>" + methodName + "</h2> \n");
List<ServiceFactory.ServiceMethodEntry> entries = serviceMethodMap.get(serviceName).get(methodName);
sb.append("\t<h4>" + entries.get(0).getReturnType().getCanonicalName() + " ");
sb.append(entries.get(0).getMethod().getName() + "(");
sb.append(entries.get(0).getParamType().getCanonicalName() + ")</h4><br> \n");
serviceMethodList.add(serviceName + "." + methodName);
}
}
sb.append("\n\t<form method=\"post\" action=\"invoke\" name=\"dataform\">\n" +
"\tService: <select name=\"servicename\">\n");
for (String serviceMethod : serviceMethodList) {
sb.append("\t<option>" + serviceMethod + "</option>\n");
}
sb.append("\t</select><br>\n");
sb.append("\tRequest: <textarea name=\"reqjson\" rows=\"5\" cols=\"40\"></textarea> \n" +
"\t<a href=\"javascript:;\" onclick=\"ajaxpost()\">Invoke</a><br> \n" +
"\tResponse: <textarea name=\"rspjson\" rows=\"5\" cols=\"40\"></textarea> \n" +
"\t</form> \n" +
"\t\n" +
"\t<script type=\"text/javascript\"> \n" +
"\tfunction ajaxpost(){ \n" +
"\tvar f = document.dataform; \n" +
"\tvar req = f.reqjson.value; \n" +
"\tvar url = \"/invoke?methodName=\" + f.servicename.value;\n" +
"\n" +
"\t$.post(url, req,\n" +
"\t function(data){\n" +
"\t\tf.rspjson.value = data;\n" +
"\t },\n" +
"\t \"text\");\n" +
"\t} \n" +
"</script>\n");
sb.append("</body>\n</html>");
rpcResponse.setResultObj(sb.toString());
rpcResponse.setErrno(0);
}
public RpcResponse call() throws Exception {
setThreadContext("session", rpcContext);
RpcRequest rpcRequest = rpcContext.getRequest();
ChannelHandlerContext channelHandlerContext = rpcContext.getChannelContext();
RpcResponse rpcResponse = new RpcResponse();
rpcResponse.setSerializeMode(rpcRequest.getSerializeMode());
rpcResponse.setSeq(rpcRequest.getSeq());
rpcResponse.setResultObj(null);
rpcResponse.setError(null);
if (rpcRequest.getException() != null) {
//already exceptions for the request
rpcResponse.setErrno(-1); //invalid request
rpcResponse.setError(rpcRequest.getException());
channelHandlerContext.getChannel().write(rpcResponse);
return null;
}
if (rpcRequest.getHttpCgiName() != null && rpcRequest.getHttpCgiName().compareToIgnoreCase("/list") == 0) {
processListCgi(rpcRequest, rpcResponse);
channelHandlerContext.getChannel().write(rpcResponse);
return null;
}
//Map<String, String> headers = new HashMap<String, String>();
//headers.put("Coloring", "1");
//AccessLog.doLog(AccessLog.LOG_LEVEL_DEBUG, headers, "system rpc log. request: " + rpcRequest.getParameter());
String serviceMethodName = rpcRequest.getServiceName() + "/" + rpcRequest.getMethodName();
log.info("Rpc Call: " + rpcContext.getClientAddr() + " ---> " +
rpcContext.getLocalAddr() + " " + serviceMethodName + " request: " + rpcRequest.getParameter());
//AccessLog.doLog(AccessLog.LOG_LEVEL_INFO, "Rpc Call: " + rpcContext.getClientAddr() + " ---> " +
// rpcContext.getLocalAddr() + " " + serviceMethodName + " request: " + rpcRequest.getParameter());
ServiceFactory.ServiceMethodEntry serviceMethodEntry = ServiceFactory.getServiceMethodEntry(rpcRequest.getServiceName(), rpcRequest.getMethodName());
if (serviceMethodEntry != null) {
Object invokeResultObj = null;
try {
long timeBegin = System.currentTimeMillis();
invokeResultObj = serviceMethodEntry.invoke(rpcRequest.getParameter());
long timeEnd = System.currentTimeMillis();
log.error("Request processor time cost: " + (timeEnd - timeBegin));
rpcResponse.setErrno(0);
rpcResponse.setResultObj(invokeResultObj);
AccessMonitor.add("frm.rpc " + rpcRequest.getMethodName() + " succ count");
log.info("RPC invoke discrete method succeeded: " + invokeResultObj);
//AccessLog.doLog(AccessLog.LOG_LEVEL_INFO, "Rpc Call timecost: " + (timeEnd - timeBegin) + "ms response: " + invokeResultObj);
} catch (InvocationTargetException ex) {
rpcResponse.setErrno(-1000);
rpcResponse.setError(ex);
log.error("Invoke method failed. " + ex.getMessage());
AccessLog.doLog(AccessLog.LOG_LEVEL_ERROR, "Rpc Call exception: " + ex.getMessage());
AccessMonitor.add("frm.rpc " + rpcRequest.getMethodName() + " failed count");
} catch (IllegalAccessException ex) {
rpcResponse.setErrno(-1000);
rpcResponse.setError(ex);
log.error("Invoke method failed. " + ex.getMessage());
AccessLog.doLog(AccessLog.LOG_LEVEL_ERROR, "Rpc Call exception: " + ex.getMessage());
AccessMonitor.add("frm.rpc " + rpcRequest.getMethodName() + " failed count");
}
} else {
log.error("No service method registered: " + rpcRequest.getServiceName() + rpcRequest.getMethodName());
AccessLog.doLog(AccessLog.LOG_LEVEL_ERROR, "Rpc Call exception: No service method registered: "
+ rpcRequest.getServiceName() + rpcRequest.getMethodName());
AccessMonitor.add("frm.rpc " + rpcRequest.getMethodName() + " not registered");
AccessMonitor.add("frm.rpc " + rpcRequest.getMethodName() + " failed count");
rpcResponse.setErrno(-1);
rpcResponse.setError(new Exception("No service method registered: " +
rpcRequest.getServiceName() + rpcRequest.getMethodName()));
}
channelHandlerContext.getChannel().write(rpcResponse);
return null;
}
}