sncp
This commit is contained in:
@@ -9,7 +9,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.redkale.annotation.Param;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
|
||||
/**
|
||||
* 存放方法的字节信息
|
||||
@@ -151,6 +150,7 @@ public class AsmMethodBean {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
return "{params:" + params + ", access:" + access + ", name:" + name + ", desc:" + desc + ", signature:"
|
||||
+ signature + ", exceptions:" + exceptions + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
package org.redkale.asm;
|
||||
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.util.TypeToken;
|
||||
|
||||
/**
|
||||
@@ -67,6 +66,6 @@ public class AsmMethodParam {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
return "{name:" + name + ", description:" + description + ", signature:" + signature + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.redkale.inject.Resourcable;
|
||||
import org.redkale.inject.ResourceFactory;
|
||||
import org.redkale.mq.spi.MessageAgent;
|
||||
import org.redkale.net.http.WebSocketNode;
|
||||
import org.redkale.net.sncp.SncpRemoteInfo.SncpRemoteAction;
|
||||
import org.redkale.scheduled.Scheduled;
|
||||
import org.redkale.service.*;
|
||||
import org.redkale.util.AnyValue;
|
||||
|
||||
645
src/main/java/org/redkale/net/sncp/SncpActionServlet.java
Normal file
645
src/main/java/org/redkale/net/sncp/SncpActionServlet.java
Normal file
@@ -0,0 +1,645 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2116 Redkale
|
||||
* All rights reserved.
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.Future;
|
||||
import org.redkale.annotation.ClassDepends;
|
||||
import org.redkale.annotation.NonBlocking;
|
||||
import org.redkale.asm.ClassWriter;
|
||||
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import org.redkale.asm.Label;
|
||||
import org.redkale.asm.MethodDebugVisitor;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.asm.Type;
|
||||
import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.Reader;
|
||||
import org.redkale.convert.pb.ProtobufFactory;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.util.RedkaleClassLoader;
|
||||
import org.redkale.util.TypeToken;
|
||||
import org.redkale.util.Uint128;
|
||||
|
||||
/**
|
||||
* 每个Service方法的SncpServlet对象
|
||||
*
|
||||
* <p>详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public abstract class SncpActionServlet extends SncpServlet {
|
||||
|
||||
protected final Method method;
|
||||
|
||||
protected final Uint128 actionid;
|
||||
|
||||
protected final boolean nonBlocking;
|
||||
|
||||
@ClassDepends
|
||||
protected final java.lang.reflect.Type[] paramTypes; // 第一个元素存放返回类型return type, void的返回参数类型为null, 数组长度为:1+参数个数
|
||||
|
||||
@ClassDepends
|
||||
protected final java.lang.reflect.Type paramComposeBeanType;
|
||||
|
||||
protected final int paramHandlerIndex; // >=0表示存在CompletionHandler参数
|
||||
|
||||
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
||||
|
||||
protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型
|
||||
|
||||
@ClassDepends
|
||||
protected final java.lang.reflect.Type returnObjectType; // 返回结果类型 void必须设为null
|
||||
|
||||
@ClassDepends
|
||||
protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型
|
||||
|
||||
@ClassDepends
|
||||
protected SncpActionServlet(
|
||||
String resourceName,
|
||||
Class resourceType,
|
||||
Service service,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid);
|
||||
Objects.requireNonNull(method);
|
||||
this.actionid = actionid;
|
||||
this.method = method;
|
||||
this.paramComposeBeanType = SncpRemoteAction.createParamComposeBeanType(
|
||||
Sncp.getServiceType(service),
|
||||
method,
|
||||
actionid,
|
||||
method.getGenericParameterTypes(),
|
||||
method.getParameterTypes());
|
||||
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncClass = null;
|
||||
java.lang.reflect.Type handlerResultType = null;
|
||||
try {
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
java.lang.reflect.Type[] genericParams = method.getGenericParameterTypes();
|
||||
for (int i = 0; i < paramClasses.length; i++) { // 反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncClass = paramClasses[i];
|
||||
java.lang.reflect.Type handlerType = TypeToken.getGenericType(genericParams[i], service.getClass());
|
||||
if (handlerType instanceof Class) {
|
||||
handlerResultType = Object.class;
|
||||
} else if (handlerType instanceof ParameterizedType) {
|
||||
handlerResultType = TypeToken.getGenericType(
|
||||
((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType);
|
||||
} else {
|
||||
throw new SncpException(service.getClass() + " had unknown genericType in " + method);
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new SncpException(
|
||||
method + " have CompletionHandler type parameter but return type is not void");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
// do nothing
|
||||
}
|
||||
java.lang.reflect.Type[] originalParamTypes =
|
||||
TypeToken.getGenericType(method.getGenericParameterTypes(), service.getClass());
|
||||
java.lang.reflect.Type originalReturnType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), service.getClass());
|
||||
java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1];
|
||||
types[0] = originalReturnType;
|
||||
System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length);
|
||||
this.paramTypes = types;
|
||||
this.paramHandlerIndex = handlerFuncIndex;
|
||||
this.paramHandlerClass = handlerFuncClass;
|
||||
this.paramHandlerResultType = handlerResultType;
|
||||
this.returnObjectType =
|
||||
originalReturnType == void.class || originalReturnType == Void.class ? null : originalReturnType;
|
||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||
java.lang.reflect.Type futureType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), service.getClass());
|
||||
java.lang.reflect.Type returnType = null;
|
||||
if (futureType instanceof Class) {
|
||||
returnType = Object.class;
|
||||
} else if (futureType instanceof ParameterizedType) {
|
||||
returnType = TypeToken.getGenericType(
|
||||
((ParameterizedType) futureType).getActualTypeArguments()[0], futureType);
|
||||
} else {
|
||||
throw new SncpException(service.getClass() + " had unknown return genericType in " + method);
|
||||
}
|
||||
this.returnFutureResultType = returnType;
|
||||
} else {
|
||||
this.returnFutureResultType = null;
|
||||
}
|
||||
NonBlocking non = method.getAnnotation(NonBlocking.class);
|
||||
if (non == null) {
|
||||
non = service.getClass().getAnnotation(NonBlocking.class);
|
||||
}
|
||||
// Future代替CompletionStage 不容易判断异步
|
||||
this.nonBlocking = non == null
|
||||
&& (CompletionStage.class.isAssignableFrom(method.getReturnType()) || this.paramHandlerIndex >= 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(SncpRequest request, SncpResponse response) throws IOException {
|
||||
if (paramHandlerIndex > 0) {
|
||||
response.paramAsyncHandler(paramHandlerClass, paramHandlerResultType);
|
||||
}
|
||||
try {
|
||||
action(request, response);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void action(SncpRequest request, SncpResponse response) throws Throwable;
|
||||
|
||||
public <T extends Service> T service() {
|
||||
return (T) service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uint128 getServiceid() {
|
||||
return serviceid;
|
||||
}
|
||||
|
||||
public Uint128 getActionid() {
|
||||
return actionid;
|
||||
}
|
||||
|
||||
public String actionName() {
|
||||
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* public interface TestService extends Service {
|
||||
*
|
||||
* public boolean change(TestBean bean, String name, int id);
|
||||
*
|
||||
* public void insert(BooleanHandler handler, TestBean bean, String name, int id);
|
||||
*
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
||||
*
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @ResourceType(TestService.class)
|
||||
* public class TestServiceImpl implements TestService {
|
||||
*
|
||||
* @Override
|
||||
* public boolean change(TestBean bean, String name, int id) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
|
||||
*
|
||||
* @Override
|
||||
* public void completed(Boolean result, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void failed(Throwable exc, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_change extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_change(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* Object rs = serviceObj.change(arg1, arg2, arg3);
|
||||
* response.finish(boolean.class, rs);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_insert extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_insert(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* BooleanHandler arg0 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.insert(arg0, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_update extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_update(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
* short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
* CompletionHandler a3 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_changeName extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_changeName(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
||||
* response.finishFuture(paramHandlerResultType, future);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @param resourceName 资源名
|
||||
* @param resourceType 资源类
|
||||
* @param serviceImplClass Service实现类
|
||||
* @param service Service
|
||||
* @param serviceid 类ID
|
||||
* @param actionid 操作ID
|
||||
* @param method 方法
|
||||
* @return SncpActionServlet
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static SncpActionServlet create(
|
||||
final String resourceName,
|
||||
final Class resourceType,
|
||||
final Class serviceImplClass,
|
||||
final Service service,
|
||||
final Uint128 serviceid,
|
||||
final Uint128 actionid,
|
||||
final Method method) {
|
||||
|
||||
final Class serviceClass = service.getClass();
|
||||
final String supDynName = SncpActionServlet.class.getName().replace('.', '/');
|
||||
final String serviceImpTypeName = serviceImplClass.getName().replace('.', '/');
|
||||
final String convertName = Convert.class.getName().replace('.', '/');
|
||||
final String uint128Desc = Type.getDescriptor(Uint128.class);
|
||||
final String convertDesc = Type.getDescriptor(Convert.class);
|
||||
final String readerDesc = Type.getDescriptor(Reader.class);
|
||||
final String requestName = SncpRequest.class.getName().replace('.', '/');
|
||||
final String responseName = SncpResponse.class.getName().replace('.', '/');
|
||||
final String requestDesc = Type.getDescriptor(SncpRequest.class);
|
||||
final String responseDesc = Type.getDescriptor(SncpResponse.class);
|
||||
final String serviceDesc = Type.getDescriptor(Service.class);
|
||||
final boolean boolReturnTypeFuture = Future.class.isAssignableFrom(method.getReturnType());
|
||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__"
|
||||
+ resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
||||
|
||||
Class<?> newClazz = null;
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
newClazz = clz == null
|
||||
? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.'))
|
||||
: clz;
|
||||
} catch (Throwable ex) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
final java.lang.reflect.Type[] originalParamTypes =
|
||||
TypeToken.getGenericType(method.getGenericParameterTypes(), serviceClass);
|
||||
final java.lang.reflect.Type originalReturnType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), serviceClass);
|
||||
|
||||
if (newClazz == null) {
|
||||
// -------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||||
MethodDebugVisitor mv;
|
||||
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
|
||||
{
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(
|
||||
ACC_PUBLIC,
|
||||
"<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/Class;" + serviceDesc + uint128Desc + uint128Desc
|
||||
+ "Ljava/lang/reflect/Method;)V",
|
||||
null,
|
||||
null));
|
||||
Label label0 = new Label();
|
||||
mv.visitLabel(label0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
mv.visitVarInsn(ALOAD, 5);
|
||||
mv.visitVarInsn(ALOAD, 6);
|
||||
mv.visitMethodInsn(
|
||||
INVOKESPECIAL,
|
||||
supDynName,
|
||||
"<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/Class;" + serviceDesc + uint128Desc + uint128Desc
|
||||
+ "Ljava/lang/reflect/Method;)V",
|
||||
false);
|
||||
mv.visitInsn(RETURN);
|
||||
Label label2 = new Label();
|
||||
mv.visitLabel(label2);
|
||||
mv.visitLocalVariable("this", "L" + newDynName + ";", null, label0, label2, 0);
|
||||
mv.visitLocalVariable("resourceName", "Ljava/lang/String;", null, label0, label2, 1);
|
||||
mv.visitLocalVariable("resourceType", "Ljava/lang/Class;", null, label0, label2, 2);
|
||||
mv.visitLocalVariable("service", serviceDesc, null, label0, label2, 3);
|
||||
mv.visitLocalVariable("serviceid", uint128Desc, null, label0, label2, 4);
|
||||
mv.visitLocalVariable("actionid", uint128Desc, null, label0, label2, 5);
|
||||
mv.visitLocalVariable("method", "Ljava/lang/reflect/Method;", null, label0, label2, 6);
|
||||
mv.visitMaxs(7, 7);
|
||||
mv.visitEnd();
|
||||
}
|
||||
String convertFromDesc = "(Ljava/lang/reflect/Type;" + readerDesc + ")Ljava/lang/Object;";
|
||||
try {
|
||||
convertFromDesc = Type.getMethodDescriptor(
|
||||
Convert.class.getMethod("convertFrom", java.lang.reflect.Type.class, Reader.class));
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
{ // action方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(
|
||||
ACC_PUBLIC, "action", "(" + requestDesc + responseDesc + ")V", null, new String[] {
|
||||
"java/lang/Throwable"
|
||||
}));
|
||||
// mv.setDebug(true);
|
||||
{ // Convert
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getConvert", "()" + convertDesc, false);
|
||||
mv.visitVarInsn(ASTORE, 3);
|
||||
}
|
||||
{ // Reader
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getReader", "()" + readerDesc, false);
|
||||
mv.visitVarInsn(ASTORE, 4);
|
||||
}
|
||||
int iconst = ICONST_1;
|
||||
int intconst = 1;
|
||||
int store = 5; // action的参数个数+2
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
int[][] codes = new int[paramClasses.length][2];
|
||||
int handlerFuncIndex = -1;
|
||||
for (int i = 0; i < paramClasses.length; i++) { // 反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
if (boolReturnTypeFuture) {
|
||||
throw new SncpException(method + " have both CompletionHandler and CompletableFuture");
|
||||
}
|
||||
if (handlerFuncIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one CompletionHandler type parameter");
|
||||
}
|
||||
Sncp.checkAsyncModifier(paramClasses[i], method);
|
||||
handlerFuncIndex = i;
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
responseName,
|
||||
"getParamAsyncHandler",
|
||||
"()Ljava/nio/channels/CompletionHandler;",
|
||||
false);
|
||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
codes[i] = new int[] {ALOAD, store};
|
||||
store++;
|
||||
iconst++;
|
||||
intconst++;
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class)));
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
mv.visitInsn(POP);
|
||||
continue;
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
||||
|
||||
if (intconst < 6) {
|
||||
mv.visitInsn(ICONST_0 + intconst);
|
||||
} else if (iconst <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, intconst);
|
||||
} else if (iconst <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, intconst);
|
||||
} else {
|
||||
mv.visitLdcInsn(intconst);
|
||||
}
|
||||
mv.visitInsn(AALOAD);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
int load = ALOAD;
|
||||
int v = 0;
|
||||
if (paramClasses[i].isPrimitive()) {
|
||||
int storecode = ISTORE;
|
||||
load = ILOAD;
|
||||
if (paramClasses[i] == long.class) {
|
||||
storecode = LSTORE;
|
||||
load = LLOAD;
|
||||
v = 1;
|
||||
} else if (paramClasses[i] == float.class) {
|
||||
storecode = FSTORE;
|
||||
load = FLOAD;
|
||||
v = 1;
|
||||
} else if (paramClasses[i] == double.class) {
|
||||
storecode = DSTORE;
|
||||
load = DLOAD;
|
||||
v = 1;
|
||||
}
|
||||
Class bigPrimitiveClass = TypeToken.primitiveToWrapper(paramClasses[i]);
|
||||
String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/');
|
||||
try {
|
||||
Method pm = bigPrimitiveClass.getMethod(paramClasses[i].getSimpleName() + "Value");
|
||||
mv.visitTypeInsn(CHECKCAST, bigPrimitiveName);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
mv.visitVarInsn(storecode, store);
|
||||
} else {
|
||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store); //
|
||||
}
|
||||
codes[i] = new int[] {load, store};
|
||||
store += v;
|
||||
iconst++;
|
||||
intconst++;
|
||||
store++;
|
||||
}
|
||||
{ // 调用service
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()" + serviceDesc, false);
|
||||
mv.visitTypeInsn(CHECKCAST, serviceImpTypeName);
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
for (int[] j : codes) {
|
||||
mv.visitVarInsn(j[0], j[1]);
|
||||
}
|
||||
mv.visitMethodInsn(
|
||||
serviceImplClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL,
|
||||
serviceImpTypeName,
|
||||
method.getName(),
|
||||
Type.getMethodDescriptor(method),
|
||||
serviceImplClass.isInterface());
|
||||
store++;
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
final Class returnClass = method.getReturnType();
|
||||
if (returnClass.isPrimitive()) {
|
||||
Class bigClass = TypeToken.primitiveToWrapper(returnClass);
|
||||
try {
|
||||
Method vo = bigClass.getMethod("valueOf", returnClass);
|
||||
mv.visitMethodInsn(
|
||||
INVOKESTATIC,
|
||||
bigClass.getName().replace('.', '/'),
|
||||
vo.getName(),
|
||||
Type.getMethodDescriptor(vo),
|
||||
false);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
}
|
||||
mv.visitVarInsn(ASTORE, store); // 11
|
||||
|
||||
if (boolReturnTypeFuture) { // 返回类型为Future
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureResultType", "Ljava/lang/reflect/Type;");
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
responseName,
|
||||
"finishFuture",
|
||||
"(Ljava/lang/reflect/Type;Ljava/util/concurrent/Future;)V",
|
||||
false);
|
||||
} else if (handlerFuncIndex >= 0) { // 参数有CompletionHandler
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||
} else { // 普通对象
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", "Ljava/lang/reflect/Type;");
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
responseName,
|
||||
"finish",
|
||||
"(Ljava/lang/reflect/Type;Ljava/lang/Object;)V",
|
||||
false);
|
||||
}
|
||||
} else { // void返回类型
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||
}
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(8, store);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
byte[] bytes = cw.toByteArray();
|
||||
newClazz = new ClassLoader(serviceClass.getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||||
try {
|
||||
RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), newClazz.getField("service"));
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
for (java.lang.reflect.Type t : originalParamTypes) {
|
||||
if (t == java.io.Serializable.class
|
||||
|| t == java.io.Serializable[].class
|
||||
|| t.toString().startsWith("java.lang.")) {
|
||||
continue;
|
||||
}
|
||||
ProtobufFactory.root().loadDecoder(t);
|
||||
}
|
||||
if (originalReturnType != void.class && originalReturnType != Void.class) {
|
||||
if (boolReturnTypeFuture && method.getReturnType() != method.getGenericReturnType()) {
|
||||
java.lang.reflect.Type t =
|
||||
((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0];
|
||||
if (t != Void.class && t != java.lang.reflect.Type.class) {
|
||||
ProtobufFactory.root().loadEncoder(t);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
ProtobufFactory.root().loadEncoder(originalReturnType);
|
||||
} catch (Exception e) {
|
||||
System.err.println(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (SncpActionServlet) newClazz.getConstructors()[0].newInstance(
|
||||
resourceName, resourceType, service, serviceid, actionid, method);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
}
|
||||
}
|
||||
318
src/main/java/org/redkale/net/sncp/SncpRemoteAction.java
Normal file
318
src/main/java/org/redkale/net/sncp/SncpRemoteAction.java
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2116 Redkale
|
||||
* All rights reserved.
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import org.redkale.asm.AnnotationVisitor;
|
||||
import org.redkale.asm.AsmMethodBean;
|
||||
import org.redkale.asm.AsmMethodBoost;
|
||||
import org.redkale.asm.AsmMethodParam;
|
||||
import org.redkale.asm.Asms;
|
||||
import org.redkale.asm.ClassWriter;
|
||||
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import org.redkale.asm.FieldVisitor;
|
||||
import org.redkale.asm.MethodDebugVisitor;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.convert.ConvertColumn;
|
||||
import org.redkale.convert.ObjectEncoder;
|
||||
import org.redkale.convert.pb.ProtobufFactory;
|
||||
import org.redkale.service.RpcAttachment;
|
||||
import org.redkale.service.RpcSourceAddress;
|
||||
import org.redkale.service.RpcTargetAddress;
|
||||
import org.redkale.service.RpcTargetTopic;
|
||||
import org.redkale.util.Creator;
|
||||
import org.redkale.util.RedkaleClassLoader;
|
||||
import org.redkale.util.TypeToken;
|
||||
import org.redkale.util.Uint128;
|
||||
|
||||
/**
|
||||
* 每个Service方法的相关信息对象
|
||||
*
|
||||
* <p>详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public final class SncpRemoteAction {
|
||||
|
||||
protected final Uint128 actionid;
|
||||
|
||||
protected final Method method;
|
||||
|
||||
protected final Type returnObjectType; // void必须设为null
|
||||
|
||||
protected final Type[] paramTypes;
|
||||
|
||||
protected final Class[] paramClasses;
|
||||
|
||||
// 参数数量为0: 值为null; 参数数量为1且参数类型为JavaBean: 值为第一个参数的类型; 其他情况: 动态生成的Object类
|
||||
protected final Type paramComposeBeanType;
|
||||
|
||||
protected final int paramHandlerIndex;
|
||||
|
||||
protected final int paramHandlerAttachIndex;
|
||||
|
||||
protected final int paramAddressTargetIndex;
|
||||
|
||||
protected final int paramAddressSourceIndex;
|
||||
|
||||
protected final int paramTopicTargetIndex;
|
||||
|
||||
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
||||
|
||||
protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型
|
||||
|
||||
protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型
|
||||
|
||||
protected final Class<? extends Future> returnFutureClass; // 返回结果的CompletableFuture类型
|
||||
|
||||
protected final Creator<? extends CompletableFuture> returnFutureCreator; // 返回CompletableFuture类型的构建器
|
||||
|
||||
protected final SncpHeader header;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
SncpRemoteAction(
|
||||
final Class serviceImplClass,
|
||||
Class resourceType,
|
||||
Method method,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final SncpClient sncpClient) {
|
||||
this.actionid = actionid == null ? Sncp.actionid(method) : actionid;
|
||||
Type rt = TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass);
|
||||
this.returnObjectType = rt == void.class || rt == Void.class ? null : rt;
|
||||
this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass);
|
||||
this.paramClasses = method.getParameterTypes();
|
||||
this.paramComposeBeanType =
|
||||
createParamComposeBeanType(serviceImplClass, method, actionid, paramTypes, paramClasses);
|
||||
this.method = method;
|
||||
Annotation[][] anns = method.getParameterAnnotations();
|
||||
int topicAddrIndex = -1;
|
||||
int targetAddrIndex = -1;
|
||||
int sourceAddrIndex = -1;
|
||||
int handlerAttachIndex = -1;
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncClass = null;
|
||||
java.lang.reflect.Type handlerResultType = null;
|
||||
Class<?>[] params = method.getParameterTypes();
|
||||
Type[] genericParams = method.getGenericParameterTypes();
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (CompletionHandler.class.isAssignableFrom(params[i])) {
|
||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||
throw new SncpException(method + " have both CompletionHandler and CompletableFuture");
|
||||
}
|
||||
if (handlerFuncIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one CompletionHandler type parameter");
|
||||
}
|
||||
Sncp.checkAsyncModifier(params[i], method);
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncClass = paramClasses[i];
|
||||
java.lang.reflect.Type handlerType = TypeToken.getGenericType(genericParams[i], serviceImplClass);
|
||||
if (handlerType instanceof Class) {
|
||||
handlerResultType = Object.class;
|
||||
} else if (handlerType instanceof ParameterizedType) {
|
||||
handlerResultType = TypeToken.getGenericType(
|
||||
((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType);
|
||||
} else {
|
||||
throw new SncpException(serviceImplClass + " had unknown genericType in " + method);
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new SncpException(
|
||||
method + " have CompletionHandler type parameter but return type is not void");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (anns.length > 0) {
|
||||
for (int i = 0; i < anns.length; i++) {
|
||||
if (anns[i].length > 0) {
|
||||
for (Annotation ann : anns[i]) {
|
||||
if (ann.annotationType() == RpcAttachment.class) {
|
||||
if (handlerAttachIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one @RpcAttachment parameter");
|
||||
}
|
||||
handlerAttachIndex = i;
|
||||
} else if (ann.annotationType() == RpcTargetAddress.class) {
|
||||
if (SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
if (sourceAddrIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one @RpcTargetAddress parameter");
|
||||
} else {
|
||||
targetAddrIndex = i;
|
||||
}
|
||||
} else {
|
||||
throw new SncpException(
|
||||
method + " must be SocketAddress Type on @RpcTargetAddress parameter");
|
||||
}
|
||||
} else if (ann.annotationType() == RpcSourceAddress.class) {
|
||||
if (SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
if (sourceAddrIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one @RpcSourceAddress parameter");
|
||||
} else {
|
||||
sourceAddrIndex = i;
|
||||
}
|
||||
} else {
|
||||
throw new SncpException(
|
||||
method + " must be SocketAddress Type on @RpcSourceAddress parameter");
|
||||
}
|
||||
} else if (ann.annotationType() == RpcTargetTopic.class) {
|
||||
if (String.class.isAssignableFrom(params[i])) {
|
||||
if (sourceAddrIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one @RpcTargetTopic parameter");
|
||||
} else {
|
||||
topicAddrIndex = i;
|
||||
}
|
||||
} else {
|
||||
throw new SncpException(method + " must be String Type on @RpcTargetTopic parameter");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.paramTopicTargetIndex = topicAddrIndex;
|
||||
this.paramAddressTargetIndex = targetAddrIndex;
|
||||
this.paramAddressSourceIndex = sourceAddrIndex;
|
||||
this.paramHandlerIndex = handlerFuncIndex;
|
||||
this.paramHandlerClass = handlerFuncClass;
|
||||
this.paramHandlerResultType = handlerResultType;
|
||||
this.paramHandlerAttachIndex = handlerAttachIndex;
|
||||
this.header = SncpHeader.create(
|
||||
sncpClient == null ? null : sncpClient.getClientSncpAddress(),
|
||||
serviceid,
|
||||
resourceType.getName(),
|
||||
actionid,
|
||||
method.getName());
|
||||
if (this.paramHandlerIndex >= 0 && method.getReturnType() != void.class) {
|
||||
throw new SncpException(method + " have CompletionHandler type parameter but return type is not void");
|
||||
}
|
||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||
java.lang.reflect.Type futureType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass);
|
||||
java.lang.reflect.Type returnType = null;
|
||||
if (futureType instanceof Class) {
|
||||
returnType = Object.class;
|
||||
} else if (futureType instanceof ParameterizedType) {
|
||||
returnType = TypeToken.getGenericType(
|
||||
((ParameterizedType) futureType).getActualTypeArguments()[0], futureType);
|
||||
} else {
|
||||
throw new SncpException(serviceImplClass + " had unknown return genericType in " + method);
|
||||
}
|
||||
this.returnFutureResultType = returnType;
|
||||
this.returnFutureClass = method.getReturnType().isAssignableFrom(CompletableFuture.class)
|
||||
? CompletableFuture.class
|
||||
: (Class) method.getReturnType();
|
||||
if (method.getReturnType().isAssignableFrom(CompletableFuture.class)
|
||||
|| CompletableFuture.class.isAssignableFrom(method.getReturnType())) {
|
||||
this.returnFutureCreator = (Creator) Creator.create(this.returnFutureClass);
|
||||
} else {
|
||||
throw new SncpException(serviceImplClass + " return must be CompletableFuture or subclass");
|
||||
}
|
||||
} else {
|
||||
this.returnFutureResultType = null;
|
||||
this.returnFutureClass = null;
|
||||
this.returnFutureCreator = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String actionName() {
|
||||
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + actionid + "," + (method == null ? "null" : method.getName()) + "}";
|
||||
}
|
||||
|
||||
public static Type createParamComposeBeanType(
|
||||
Class resourceType, Method method, Uint128 actionid, Type[] paramTypes, Class[] paramClasses) {
|
||||
if (paramTypes == null || paramTypes.length == 0) {
|
||||
return null;
|
||||
}
|
||||
if (paramTypes.length == 1 && ProtobufFactory.root().createEncoder(paramTypes[0]) instanceof ObjectEncoder) {
|
||||
return paramTypes[0];
|
||||
}
|
||||
|
||||
// 动态生成组合JavaBean类
|
||||
final Class serviceClass = resourceType.getClass();
|
||||
final String columnDesc = org.redkale.asm.Type.getDescriptor(ConvertColumn.class);
|
||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionParamBean__"
|
||||
+ resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
Class<?> newClazz = clz == null
|
||||
? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.'))
|
||||
: clz;
|
||||
return newClazz;
|
||||
} catch (Throwable ex) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(resourceType);
|
||||
AsmMethodBean methodBean = Objects.requireNonNull(methodBeans.get(AsmMethodBoost.getMethodBeanKey(method)));
|
||||
// -------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
MethodDebugVisitor mv;
|
||||
AnnotationVisitor av;
|
||||
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, "java/lang/Object", null);
|
||||
final List<AsmMethodParam> asmParams = methodBean.getParams();
|
||||
for (int i = 1; i <= paramClasses.length; i++) {
|
||||
AsmMethodParam param = asmParams.get(i - 1);
|
||||
String paramDesc = org.redkale.asm.Type.getDescriptor(paramClasses[i - 1]);
|
||||
fv = cw.visitField(ACC_PUBLIC, "arg" + i, paramDesc, param.getSignature(), null);
|
||||
av = fv.visitAnnotation(columnDesc, true);
|
||||
av.visit("index", i);
|
||||
av.visitEnd();
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ // 空参数构造函数
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // 带参数构造函数
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "([Ljava/lang/Object;)V", null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
for (int i = 1; i <= paramClasses.length; i++) {
|
||||
String paramDesc = org.redkale.asm.Type.getDescriptor(paramClasses[i - 1]);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
Asms.visitInsn(mv, i - 1);
|
||||
mv.visitInsn(AALOAD);
|
||||
Asms.visitCheckCast(mv, paramClasses[i - 1]);
|
||||
mv.visitFieldInsn(PUTFIELD, newDynName, "arg" + i, paramDesc);
|
||||
}
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
byte[] bytes = cw.toByteArray();
|
||||
Class newClazz = new ClassLoader(serviceClass.getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||||
return newClazz;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
package org.redkale.net.sncp;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -348,194 +347,4 @@ public class SncpRemoteInfo<S extends Service> {
|
||||
public Set<InetSocketAddress> getRemoteAddresses() {
|
||||
return remoteAddresses;
|
||||
}
|
||||
|
||||
public static final class SncpRemoteAction {
|
||||
|
||||
protected final Uint128 actionid;
|
||||
|
||||
protected final Method method;
|
||||
|
||||
protected final Type returnObjectType; // void必须设为null
|
||||
|
||||
protected final Type[] paramTypes;
|
||||
|
||||
protected final Class[] paramClasses;
|
||||
|
||||
protected final int paramHandlerIndex;
|
||||
|
||||
protected final int paramHandlerAttachIndex;
|
||||
|
||||
protected final int paramAddressTargetIndex;
|
||||
|
||||
protected final int paramAddressSourceIndex;
|
||||
|
||||
protected final int paramTopicTargetIndex;
|
||||
|
||||
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
||||
|
||||
protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型
|
||||
|
||||
protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型
|
||||
|
||||
protected final Class<? extends Future> returnFutureClass; // 返回结果的CompletableFuture类型
|
||||
|
||||
protected final Creator<? extends CompletableFuture> returnFutureCreator; // 返回CompletableFuture类型的构建器
|
||||
|
||||
protected final SncpHeader header;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
SncpRemoteAction(
|
||||
final Class serviceImplClass,
|
||||
Class resourceType,
|
||||
Method method,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final SncpClient sncpClient) {
|
||||
this.actionid = actionid == null ? Sncp.actionid(method) : actionid;
|
||||
Type rt = TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass);
|
||||
this.returnObjectType = rt == void.class || rt == Void.class ? null : rt;
|
||||
this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass);
|
||||
this.paramClasses = method.getParameterTypes();
|
||||
this.method = method;
|
||||
Annotation[][] anns = method.getParameterAnnotations();
|
||||
int topicAddrIndex = -1;
|
||||
int targetAddrIndex = -1;
|
||||
int sourceAddrIndex = -1;
|
||||
int handlerAttachIndex = -1;
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncClass = null;
|
||||
java.lang.reflect.Type handlerResultType = null;
|
||||
Class<?>[] params = method.getParameterTypes();
|
||||
Type[] genericParams = method.getGenericParameterTypes();
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (CompletionHandler.class.isAssignableFrom(params[i])) {
|
||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||
throw new SncpException(method + " have both CompletionHandler and CompletableFuture");
|
||||
}
|
||||
if (handlerFuncIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one CompletionHandler type parameter");
|
||||
}
|
||||
Sncp.checkAsyncModifier(params[i], method);
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncClass = paramClasses[i];
|
||||
java.lang.reflect.Type handlerType = TypeToken.getGenericType(genericParams[i], serviceImplClass);
|
||||
if (handlerType instanceof Class) {
|
||||
handlerResultType = Object.class;
|
||||
} else if (handlerType instanceof ParameterizedType) {
|
||||
handlerResultType = TypeToken.getGenericType(
|
||||
((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType);
|
||||
} else {
|
||||
throw new SncpException(serviceImplClass + " had unknown genericType in " + method);
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new SncpException(
|
||||
method + " have CompletionHandler type parameter but return type is not void");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (anns.length > 0) {
|
||||
for (int i = 0; i < anns.length; i++) {
|
||||
if (anns[i].length > 0) {
|
||||
for (Annotation ann : anns[i]) {
|
||||
if (ann.annotationType() == RpcAttachment.class) {
|
||||
if (handlerAttachIndex >= 0) {
|
||||
throw new SncpException(method + " have more than one @RpcAttachment parameter");
|
||||
}
|
||||
handlerAttachIndex = i;
|
||||
} else if (ann.annotationType() == RpcTargetAddress.class) {
|
||||
if (SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
if (sourceAddrIndex >= 0) {
|
||||
throw new SncpException(
|
||||
method + " have more than one @RpcTargetAddress parameter");
|
||||
} else {
|
||||
targetAddrIndex = i;
|
||||
}
|
||||
} else {
|
||||
throw new SncpException(
|
||||
method + " must be SocketAddress Type on @RpcTargetAddress parameter");
|
||||
}
|
||||
} else if (ann.annotationType() == RpcSourceAddress.class) {
|
||||
if (SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
if (sourceAddrIndex >= 0) {
|
||||
throw new SncpException(
|
||||
method + " have more than one @RpcSourceAddress parameter");
|
||||
} else {
|
||||
sourceAddrIndex = i;
|
||||
}
|
||||
} else {
|
||||
throw new SncpException(
|
||||
method + " must be SocketAddress Type on @RpcSourceAddress parameter");
|
||||
}
|
||||
} else if (ann.annotationType() == RpcTargetTopic.class) {
|
||||
if (String.class.isAssignableFrom(params[i])) {
|
||||
if (sourceAddrIndex >= 0) {
|
||||
throw new SncpException(
|
||||
method + " have more than one @RpcTargetTopic parameter");
|
||||
} else {
|
||||
topicAddrIndex = i;
|
||||
}
|
||||
} else {
|
||||
throw new SncpException(
|
||||
method + " must be String Type on @RpcTargetTopic parameter");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.paramTopicTargetIndex = topicAddrIndex;
|
||||
this.paramAddressTargetIndex = targetAddrIndex;
|
||||
this.paramAddressSourceIndex = sourceAddrIndex;
|
||||
this.paramHandlerIndex = handlerFuncIndex;
|
||||
this.paramHandlerClass = handlerFuncClass;
|
||||
this.paramHandlerResultType = handlerResultType;
|
||||
this.paramHandlerAttachIndex = handlerAttachIndex;
|
||||
this.header = SncpHeader.create(
|
||||
sncpClient == null ? null : sncpClient.getClientSncpAddress(),
|
||||
serviceid,
|
||||
resourceType.getName(),
|
||||
actionid,
|
||||
method.getName());
|
||||
if (this.paramHandlerIndex >= 0 && method.getReturnType() != void.class) {
|
||||
throw new SncpException(method + " have CompletionHandler type parameter but return type is not void");
|
||||
}
|
||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||
java.lang.reflect.Type futureType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass);
|
||||
java.lang.reflect.Type returnType = null;
|
||||
if (futureType instanceof Class) {
|
||||
returnType = Object.class;
|
||||
} else if (futureType instanceof ParameterizedType) {
|
||||
returnType = TypeToken.getGenericType(
|
||||
((ParameterizedType) futureType).getActualTypeArguments()[0], futureType);
|
||||
} else {
|
||||
throw new SncpException(serviceImplClass + " had unknown return genericType in " + method);
|
||||
}
|
||||
this.returnFutureResultType = returnType;
|
||||
this.returnFutureClass = method.getReturnType().isAssignableFrom(CompletableFuture.class)
|
||||
? CompletableFuture.class
|
||||
: (Class) method.getReturnType();
|
||||
if (method.getReturnType().isAssignableFrom(CompletableFuture.class)
|
||||
|| CompletableFuture.class.isAssignableFrom(method.getReturnType())) {
|
||||
this.returnFutureCreator = (Creator) Creator.create(this.returnFutureClass);
|
||||
} else {
|
||||
throw new SncpException(serviceImplClass + " return must be CompletableFuture or subclass");
|
||||
}
|
||||
} else {
|
||||
this.returnFutureResultType = null;
|
||||
this.returnFutureClass = null;
|
||||
this.returnFutureCreator = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String actionName() {
|
||||
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + actionid + "," + (method == null ? "null" : method.getName()) + "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ public class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
finish(RETCODE_THROWEXCEPTION, null);
|
||||
}
|
||||
|
||||
@ClassDepends
|
||||
public final void finishVoid() {
|
||||
int headerSize = SncpHeader.calcHeaderSize(request);
|
||||
ProtobufWriter out = getWriter();
|
||||
@@ -146,6 +147,7 @@ public class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
finish(0, out);
|
||||
}
|
||||
|
||||
@ClassDepends
|
||||
public final void finishFuture(final Type futureResultType, final Future future) {
|
||||
if (future == null) {
|
||||
finishVoid();
|
||||
|
||||
@@ -7,17 +7,9 @@ package org.redkale.net.sncp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import org.redkale.annotation.NonBlocking;
|
||||
import org.redkale.asm.*;
|
||||
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.asm.Type;
|
||||
import org.redkale.convert.*;
|
||||
import org.redkale.convert.pb.ProtobufFactory;
|
||||
import org.redkale.net.*;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.util.*;
|
||||
@@ -39,7 +31,7 @@ public class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse>
|
||||
|
||||
private final HashMap<Uint128, SncpActionServlet> actions = new HashMap<>();
|
||||
|
||||
private SncpServlet(String resourceName, Class resourceType, Service service, Uint128 serviceid) {
|
||||
protected SncpServlet(String resourceName, Class resourceType, Service service, Uint128 serviceid) {
|
||||
Objects.requireNonNull(resourceName);
|
||||
Objects.requireNonNull(resourceType);
|
||||
Objects.requireNonNull(service);
|
||||
@@ -194,601 +186,4 @@ public class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse>
|
||||
public final int hashCode() {
|
||||
return Objects.hashCode(getServiceid());
|
||||
}
|
||||
|
||||
public abstract static class SncpActionServlet extends SncpServlet {
|
||||
|
||||
protected final Method method;
|
||||
|
||||
protected final Uint128 actionid;
|
||||
|
||||
protected final boolean nonBlocking;
|
||||
|
||||
protected final java.lang.reflect.Type[] paramTypes; // 第一个元素存放返回类型return type, void的返回参数类型为null, 数组长度为:1+参数个数
|
||||
|
||||
protected final java.lang.reflect.Type returnObjectType; // 返回结果类型 void必须设为null
|
||||
|
||||
protected final int paramHandlerIndex; // >=0表示存在CompletionHandler参数
|
||||
|
||||
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
||||
|
||||
protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型
|
||||
|
||||
protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型
|
||||
|
||||
protected final java.lang.reflect.Type paramComposeType;
|
||||
|
||||
protected SncpActionServlet(
|
||||
String resourceName,
|
||||
Class resourceType,
|
||||
Service service,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid);
|
||||
Objects.requireNonNull(method);
|
||||
this.actionid = actionid;
|
||||
this.method = method;
|
||||
this.paramComposeType = null; // 待实现
|
||||
|
||||
int handlerFuncIndex = -1;
|
||||
Class handlerFuncClass = null;
|
||||
java.lang.reflect.Type handlerResultType = null;
|
||||
try {
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
java.lang.reflect.Type[] genericParams = method.getGenericParameterTypes();
|
||||
for (int i = 0; i < paramClasses.length; i++) { // 反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
handlerFuncIndex = i;
|
||||
handlerFuncClass = paramClasses[i];
|
||||
java.lang.reflect.Type handlerType =
|
||||
TypeToken.getGenericType(genericParams[i], service.getClass());
|
||||
if (handlerType instanceof Class) {
|
||||
handlerResultType = Object.class;
|
||||
} else if (handlerType instanceof ParameterizedType) {
|
||||
handlerResultType = TypeToken.getGenericType(
|
||||
((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType);
|
||||
} else {
|
||||
throw new SncpException(service.getClass() + " had unknown genericType in " + method);
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new SncpException(
|
||||
method + " have CompletionHandler type parameter but return type is not void");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
// do nothing
|
||||
}
|
||||
java.lang.reflect.Type[] originalParamTypes =
|
||||
TypeToken.getGenericType(method.getGenericParameterTypes(), service.getClass());
|
||||
java.lang.reflect.Type originalReturnType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), service.getClass());
|
||||
java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1];
|
||||
types[0] = originalReturnType;
|
||||
System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length);
|
||||
this.paramTypes = types;
|
||||
this.paramHandlerIndex = handlerFuncIndex;
|
||||
this.paramHandlerClass = handlerFuncClass;
|
||||
this.paramHandlerResultType = handlerResultType;
|
||||
this.returnObjectType =
|
||||
originalReturnType == void.class || originalReturnType == Void.class ? null : originalReturnType;
|
||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||
java.lang.reflect.Type futureType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), service.getClass());
|
||||
java.lang.reflect.Type returnType = null;
|
||||
if (futureType instanceof Class) {
|
||||
returnType = Object.class;
|
||||
} else if (futureType instanceof ParameterizedType) {
|
||||
returnType = TypeToken.getGenericType(
|
||||
((ParameterizedType) futureType).getActualTypeArguments()[0], futureType);
|
||||
} else {
|
||||
throw new SncpException(service.getClass() + " had unknown return genericType in " + method);
|
||||
}
|
||||
this.returnFutureResultType = returnType;
|
||||
} else {
|
||||
this.returnFutureResultType = null;
|
||||
}
|
||||
NonBlocking non = method.getAnnotation(NonBlocking.class);
|
||||
if (non == null) {
|
||||
non = service.getClass().getAnnotation(NonBlocking.class);
|
||||
}
|
||||
// Future代替CompletionStage 不容易判断异步
|
||||
this.nonBlocking = non == null
|
||||
&& (CompletionStage.class.isAssignableFrom(method.getReturnType()) || this.paramHandlerIndex >= 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(SncpRequest request, SncpResponse response) throws IOException {
|
||||
if (paramHandlerIndex > 0) {
|
||||
response.paramAsyncHandler(paramHandlerClass, paramHandlerResultType);
|
||||
}
|
||||
try {
|
||||
action(request, response);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void action(SncpRequest request, SncpResponse response) throws Throwable;
|
||||
|
||||
public <T extends Service> T service() {
|
||||
return (T) service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uint128 getServiceid() {
|
||||
return serviceid;
|
||||
}
|
||||
|
||||
public Uint128 getActionid() {
|
||||
return actionid;
|
||||
}
|
||||
|
||||
public String actionName() {
|
||||
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* public interface TestService extends Service {
|
||||
*
|
||||
* public boolean change(TestBean bean, String name, int id);
|
||||
*
|
||||
* public void insert(BooleanHandler handler, TestBean bean, String name, int id);
|
||||
*
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
||||
*
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @ResourceType(TestService.class)
|
||||
* public class TestServiceImpl implements TestService {
|
||||
*
|
||||
* @Override
|
||||
* public boolean change(TestBean bean, String name, int id) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
|
||||
*
|
||||
* @Override
|
||||
* public void completed(Boolean result, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void failed(Throwable exc, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_change extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_change(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* Object rs = serviceObj.change(arg1, arg2, arg3);
|
||||
* response.finish(boolean.class, rs);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_insert extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_insert(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* BooleanHandler arg0 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.insert(arg0, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_update extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_update(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
* short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
* CompletionHandler a3 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class DynActionTestService_changeName extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_changeName(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
||||
* response.finishFuture(paramHandlerResultType, future);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @param resourceName 资源名
|
||||
* @param resourceType 资源类
|
||||
* @param serviceImplClass Service实现类
|
||||
* @param service Service
|
||||
* @param serviceid 类ID
|
||||
* @param actionid 操作ID
|
||||
* @param method 方法
|
||||
* @return SncpActionServlet
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static SncpActionServlet create(
|
||||
final String resourceName,
|
||||
final Class resourceType,
|
||||
final Class serviceImplClass,
|
||||
final Service service,
|
||||
final Uint128 serviceid,
|
||||
final Uint128 actionid,
|
||||
final Method method) {
|
||||
|
||||
final Class serviceClass = service.getClass();
|
||||
final String supDynName = SncpActionServlet.class.getName().replace('.', '/');
|
||||
final String serviceImpTypeName = serviceImplClass.getName().replace('.', '/');
|
||||
final String convertName = Convert.class.getName().replace('.', '/');
|
||||
final String uint128Desc = Type.getDescriptor(Uint128.class);
|
||||
final String convertDesc = Type.getDescriptor(Convert.class);
|
||||
final String readerDesc = Type.getDescriptor(Reader.class);
|
||||
final String requestName = SncpRequest.class.getName().replace('.', '/');
|
||||
final String responseName = SncpResponse.class.getName().replace('.', '/');
|
||||
final String requestDesc = Type.getDescriptor(SncpRequest.class);
|
||||
final String responseDesc = Type.getDescriptor(SncpResponse.class);
|
||||
final String serviceDesc = Type.getDescriptor(Service.class);
|
||||
final boolean boolReturnTypeFuture = Future.class.isAssignableFrom(method.getReturnType());
|
||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__"
|
||||
+ resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
||||
|
||||
Class<?> newClazz = null;
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
newClazz = clz == null
|
||||
? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.'))
|
||||
: clz;
|
||||
} catch (Throwable ex) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
final java.lang.reflect.Type[] originalParamTypes =
|
||||
TypeToken.getGenericType(method.getGenericParameterTypes(), serviceClass);
|
||||
final java.lang.reflect.Type originalReturnType =
|
||||
TypeToken.getGenericType(method.getGenericReturnType(), serviceClass);
|
||||
if (newClazz == null) {
|
||||
// -------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||||
MethodDebugVisitor mv;
|
||||
|
||||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
|
||||
{
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(
|
||||
ACC_PUBLIC,
|
||||
"<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/Class;" + serviceDesc + uint128Desc + uint128Desc
|
||||
+ "Ljava/lang/reflect/Method;)V",
|
||||
null,
|
||||
null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
mv.visitVarInsn(ALOAD, 5);
|
||||
mv.visitVarInsn(ALOAD, 6);
|
||||
mv.visitMethodInsn(
|
||||
INVOKESPECIAL,
|
||||
supDynName,
|
||||
"<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/Class;" + serviceDesc + uint128Desc + uint128Desc
|
||||
+ "Ljava/lang/reflect/Method;)V",
|
||||
false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(7, 7);
|
||||
mv.visitEnd();
|
||||
}
|
||||
String convertFromDesc = "(Ljava/lang/reflect/Type;" + readerDesc + ")Ljava/lang/Object;";
|
||||
try {
|
||||
convertFromDesc = Type.getMethodDescriptor(
|
||||
Convert.class.getMethod("convertFrom", java.lang.reflect.Type.class, Reader.class));
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
{ // action方法
|
||||
mv = new MethodDebugVisitor(cw.visitMethod(
|
||||
ACC_PUBLIC, "action", "(" + requestDesc + responseDesc + ")V", null, new String[] {
|
||||
"java/lang/Throwable"
|
||||
}));
|
||||
// mv.setDebug(true);
|
||||
{ // Convert
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getConvert", "()" + convertDesc, false);
|
||||
mv.visitVarInsn(ASTORE, 3);
|
||||
}
|
||||
{ // Reader
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getReader", "()" + readerDesc, false);
|
||||
mv.visitVarInsn(ASTORE, 4);
|
||||
}
|
||||
int iconst = ICONST_1;
|
||||
int intconst = 1;
|
||||
int store = 5; // action的参数个数+2
|
||||
final Class[] paramClasses = method.getParameterTypes();
|
||||
int[][] codes = new int[paramClasses.length][2];
|
||||
int handlerFuncIndex = -1;
|
||||
for (int i = 0; i < paramClasses.length; i++) { // 反序列化方法的每个参数
|
||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||
if (boolReturnTypeFuture) {
|
||||
throw new SncpException(method + " have both CompletionHandler and CompletableFuture");
|
||||
}
|
||||
if (handlerFuncIndex >= 0) {
|
||||
throw new SncpException(
|
||||
method + " have more than one CompletionHandler type parameter");
|
||||
}
|
||||
Sncp.checkAsyncModifier(paramClasses[i], method);
|
||||
handlerFuncIndex = i;
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
responseName,
|
||||
"getParamAsyncHandler",
|
||||
"()Ljava/nio/channels/CompletionHandler;",
|
||||
false);
|
||||
mv.visitTypeInsn(
|
||||
CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
codes[i] = new int[] {ALOAD, store};
|
||||
store++;
|
||||
iconst++;
|
||||
intconst++;
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class)));
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
mv.visitInsn(POP);
|
||||
continue;
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
||||
|
||||
if (intconst < 6) {
|
||||
mv.visitInsn(ICONST_0 + intconst);
|
||||
} else if (iconst <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, intconst);
|
||||
} else if (iconst <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, intconst);
|
||||
} else {
|
||||
mv.visitLdcInsn(intconst);
|
||||
}
|
||||
mv.visitInsn(AALOAD);
|
||||
mv.visitVarInsn(ALOAD, 4);
|
||||
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
int load = ALOAD;
|
||||
int v = 0;
|
||||
if (paramClasses[i].isPrimitive()) {
|
||||
int storecode = ISTORE;
|
||||
load = ILOAD;
|
||||
if (paramClasses[i] == long.class) {
|
||||
storecode = LSTORE;
|
||||
load = LLOAD;
|
||||
v = 1;
|
||||
} else if (paramClasses[i] == float.class) {
|
||||
storecode = FSTORE;
|
||||
load = FLOAD;
|
||||
v = 1;
|
||||
} else if (paramClasses[i] == double.class) {
|
||||
storecode = DSTORE;
|
||||
load = DLOAD;
|
||||
v = 1;
|
||||
}
|
||||
Class bigPrimitiveClass = TypeToken.primitiveToWrapper(paramClasses[i]);
|
||||
String bigPrimitiveName =
|
||||
bigPrimitiveClass.getName().replace('.', '/');
|
||||
try {
|
||||
Method pm = bigPrimitiveClass.getMethod(paramClasses[i].getSimpleName() + "Value");
|
||||
mv.visitTypeInsn(CHECKCAST, bigPrimitiveName);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
bigPrimitiveName,
|
||||
pm.getName(),
|
||||
Type.getMethodDescriptor(pm),
|
||||
false);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
mv.visitVarInsn(storecode, store);
|
||||
} else {
|
||||
mv.visitTypeInsn(
|
||||
CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, store); //
|
||||
}
|
||||
codes[i] = new int[] {load, store};
|
||||
store += v;
|
||||
iconst++;
|
||||
intconst++;
|
||||
store++;
|
||||
}
|
||||
{ // 调用service
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()" + serviceDesc, false);
|
||||
mv.visitTypeInsn(CHECKCAST, serviceImpTypeName);
|
||||
mv.visitVarInsn(ASTORE, store);
|
||||
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
for (int[] j : codes) {
|
||||
mv.visitVarInsn(j[0], j[1]);
|
||||
}
|
||||
mv.visitMethodInsn(
|
||||
serviceImplClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL,
|
||||
serviceImpTypeName,
|
||||
method.getName(),
|
||||
Type.getMethodDescriptor(method),
|
||||
serviceImplClass.isInterface());
|
||||
store++;
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
final Class returnClass = method.getReturnType();
|
||||
if (returnClass.isPrimitive()) {
|
||||
Class bigClass = TypeToken.primitiveToWrapper(returnClass);
|
||||
try {
|
||||
Method vo = bigClass.getMethod("valueOf", returnClass);
|
||||
mv.visitMethodInsn(
|
||||
INVOKESTATIC,
|
||||
bigClass.getName().replace('.', '/'),
|
||||
vo.getName(),
|
||||
Type.getMethodDescriptor(vo),
|
||||
false);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
}
|
||||
mv.visitVarInsn(ASTORE, store); // 11
|
||||
|
||||
if (boolReturnTypeFuture) { // 返回类型为Future
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(
|
||||
GETFIELD, newDynName, "returnFutureResultType", "Ljava/lang/reflect/Type;");
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
responseName,
|
||||
"finishFuture",
|
||||
"(Ljava/lang/reflect/Type;Ljava/util/concurrent/Future;)V",
|
||||
false);
|
||||
} else if (handlerFuncIndex >= 0) { // 参数有CompletionHandler
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||
} else { // 普通对象
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", "Ljava/lang/reflect/Type;");
|
||||
mv.visitVarInsn(ALOAD, store);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
responseName,
|
||||
"finish",
|
||||
"(Ljava/lang/reflect/Type;Ljava/lang/Object;)V",
|
||||
false);
|
||||
}
|
||||
} else { // void返回类型
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||
}
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(8, store);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
byte[] bytes = cw.toByteArray();
|
||||
newClazz = new ClassLoader(serviceClass.getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||||
try {
|
||||
RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), newClazz.getField("service"));
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
for (java.lang.reflect.Type t : originalParamTypes) {
|
||||
if (t == java.io.Serializable.class
|
||||
|| t == java.io.Serializable[].class
|
||||
|| t.toString().startsWith("java.lang.")) {
|
||||
continue;
|
||||
}
|
||||
ProtobufFactory.root().loadDecoder(t);
|
||||
}
|
||||
if (originalReturnType != void.class && originalReturnType != Void.class) {
|
||||
if (boolReturnTypeFuture && method.getReturnType() != method.getGenericReturnType()) {
|
||||
java.lang.reflect.Type t =
|
||||
((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0];
|
||||
if (t != Void.class && t != java.lang.reflect.Type.class) {
|
||||
ProtobufFactory.root().loadEncoder(t);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
ProtobufFactory.root().loadEncoder(originalReturnType);
|
||||
} catch (Exception e) {
|
||||
System.err.println(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (SncpActionServlet) newClazz.getConstructors()[0].newInstance(
|
||||
resourceName, resourceType, service, serviceid, actionid, method);
|
||||
} catch (Exception ex) {
|
||||
throw new SncpException(ex); // 不可能会发生
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
*/
|
||||
package org.redkale.util;
|
||||
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
@@ -15,6 +13,7 @@ import java.util.concurrent.*;
|
||||
import java.util.function.*;
|
||||
import org.redkale.annotation.ConstructorParameters;
|
||||
import org.redkale.asm.*;
|
||||
import static org.redkale.asm.Opcodes.*;
|
||||
import org.redkale.asm.Type;
|
||||
|
||||
/**
|
||||
@@ -385,7 +384,7 @@ public interface Creator<T> {
|
||||
throw new RedkaleException(
|
||||
"[" + clazz + "] have no public or ConstructorParameters-Annotation constructor.");
|
||||
}
|
||||
final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
@@ -410,29 +409,13 @@ public interface Creator<T> {
|
||||
{ // paramTypes 方法
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "paramTypes", "()[Ljava/lang/Class;", null, null);
|
||||
int paramLen = constructorParameters.length;
|
||||
if (paramLen < 6) {
|
||||
mv.visitInsn(ICONST_0 + paramLen);
|
||||
} else if (paramLen <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, paramLen);
|
||||
} else if (paramLen <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, paramLen);
|
||||
} else {
|
||||
mv.visitLdcInsn(paramLen);
|
||||
}
|
||||
Asms.visitInsn(mv, paramLen);
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
|
||||
|
||||
for (int i = 0; i < constructorParameters.length; i++) {
|
||||
final Class pt = constructorParameters[i].getValue();
|
||||
mv.visitInsn(DUP);
|
||||
if (i < 6) {
|
||||
mv.visitInsn(iconsts[i]);
|
||||
} else if (i <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, i);
|
||||
} else if (i <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, i);
|
||||
} else {
|
||||
mv.visitLdcInsn(i);
|
||||
}
|
||||
Asms.visitInsn(mv, i);
|
||||
Asms.visitFieldInsn(mv, pt);
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
@@ -459,28 +442,12 @@ public interface Creator<T> {
|
||||
continue;
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
if (i < 6) {
|
||||
mv.visitInsn(iconsts[i]);
|
||||
} else if (i <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, i);
|
||||
} else if (i <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, i);
|
||||
} else {
|
||||
mv.visitLdcInsn(i);
|
||||
}
|
||||
Asms.visitInsn(mv, i);
|
||||
mv.visitInsn(AALOAD);
|
||||
Label lab = new Label();
|
||||
mv.visitJumpInsn(IFNONNULL, lab);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
if (i < 6) {
|
||||
mv.visitInsn(iconsts[i]);
|
||||
} else if (i <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, i);
|
||||
} else if (i <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, i);
|
||||
} else {
|
||||
mv.visitLdcInsn(i);
|
||||
}
|
||||
Asms.visitInsn(mv, i);
|
||||
if (pt == int.class) {
|
||||
mv.visitInsn(ICONST_0);
|
||||
mv.visitMethodInsn(
|
||||
@@ -517,15 +484,7 @@ public interface Creator<T> {
|
||||
{
|
||||
for (int i = 0; i < constructorParameters.length; i++) {
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
if (i < 6) {
|
||||
mv.visitInsn(iconsts[i]);
|
||||
} else if (i <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, i);
|
||||
} else if (i <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, i);
|
||||
} else {
|
||||
mv.visitLdcInsn(i);
|
||||
}
|
||||
Asms.visitInsn(mv, i);
|
||||
mv.visitInsn(AALOAD);
|
||||
final Class ct = constructorParameters[i].getValue();
|
||||
if (ct.isPrimitive()) {
|
||||
|
||||
@@ -16,11 +16,8 @@ import org.redkale.util.*;
|
||||
/** @author zhangjx */
|
||||
public class SncpClientCodecTest {
|
||||
|
||||
private boolean main;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
SncpClientCodecTest test = new SncpClientCodecTest();
|
||||
test.main = true;
|
||||
test.run();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,9 @@ import org.redkale.net.sncp.SncpAsyncHandler;
|
||||
/** @author zhangjx */
|
||||
public class SncpHandlerTest {
|
||||
|
||||
private boolean main;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
SncpHandlerTest test = new SncpHandlerTest();
|
||||
test.main = true;
|
||||
|
||||
test.run();
|
||||
}
|
||||
|
||||
@@ -25,9 +23,7 @@ public class SncpHandlerTest {
|
||||
SncpAsyncHandler.createHandler(CompletionHandler.class, new CompletionHandler() {
|
||||
@Override
|
||||
public void completed(Object result, Object attachment) {
|
||||
if (main) {
|
||||
System.out.println("handler result: " + result + ", attachment: " + attachment);
|
||||
}
|
||||
System.out.println("handler result: " + result + ", attachment: " + attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,11 +16,8 @@ import org.redkale.util.*;
|
||||
/** @author zhangjx */
|
||||
public class SncpRequestParseTest {
|
||||
|
||||
private boolean main;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
SncpRequestParseTest test = new SncpRequestParseTest();
|
||||
test.main = true;
|
||||
test.run();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.redkale.test.sncp;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import org.junit.jupiter.api.*;
|
||||
@@ -64,7 +62,7 @@ public class SncpSleepTest {
|
||||
CompletableFuture.allOf(futures).join();
|
||||
long e = System.currentTimeMillis() - s;
|
||||
System.out.println("耗时: " + e + " ms");
|
||||
remoteCService.test(333L, new String[] {"aaa", "bbb"}, List.of(new File("D:/a.txt"), new File("D:/b.txt")));
|
||||
//remoteCService.test(333L, new String[] {"aaa", "bbb"}, List.of(new File("D:/a.txt"), new File("D:/b.txt")));
|
||||
server.shutdown();
|
||||
workExecutor.shutdown();
|
||||
Assertions.assertTrue(e < 600);
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.test.sncp;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.redkale.annotation.ResourceType;
|
||||
import org.redkale.convert.*;
|
||||
import org.redkale.net.sncp.*;
|
||||
import org.redkale.net.sncp.SncpServlet.SncpActionServlet;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.test.util.TestBean;
|
||||
import org.redkale.util.Uint128;
|
||||
|
||||
/** @author zhangjx */
|
||||
public interface TestService extends Service {
|
||||
|
||||
public boolean change(TestBean bean, String name, int id);
|
||||
|
||||
public void insert(BooleanHandler handler, TestBean bean, String name, int id);
|
||||
|
||||
public void update(
|
||||
long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
||||
|
||||
public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
||||
}
|
||||
|
||||
@ResourceType(TestService.class)
|
||||
class TestServiceImpl implements TestService {
|
||||
|
||||
@Override
|
||||
public boolean change(TestBean bean, String name, int id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void delete(TestBean bean) {}
|
||||
|
||||
@Override
|
||||
public void insert(BooleanHandler handler, TestBean bean, String name, int id) {}
|
||||
|
||||
@Override
|
||||
public void update(
|
||||
long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
|
||||
|
||||
@Override
|
||||
public void completed(Boolean result, TestBean attachment) {}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, TestBean attachment) {}
|
||||
}
|
||||
|
||||
class DynActionTestService_change extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_change(
|
||||
String resourceName,
|
||||
Class resourceType,
|
||||
Service service,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
Object rs = serviceObj.change(arg1, arg2, arg3);
|
||||
response.finish(boolean.class, rs);
|
||||
}
|
||||
}
|
||||
|
||||
class DynActionTestService_insert extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_insert(
|
||||
String resourceName,
|
||||
Class resourceType,
|
||||
Service service,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
BooleanHandler arg0 = response.getParamAsyncHandler();
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
serviceObj.insert(arg0, arg1, arg2, arg3);
|
||||
response.finishVoid();
|
||||
}
|
||||
}
|
||||
|
||||
class DynActionTestService_update extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_update(
|
||||
String resourceName,
|
||||
Class resourceType,
|
||||
Service service,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
CompletionHandler a3 = response.getParamAsyncHandler();
|
||||
convert.convertFrom(CompletionHandler.class, in);
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
response.finishVoid();
|
||||
}
|
||||
}
|
||||
|
||||
class DynActionTestService_changeName extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_changeName(
|
||||
String resourceName,
|
||||
Class resourceType,
|
||||
Service service,
|
||||
Uint128 serviceid,
|
||||
Uint128 actionid,
|
||||
final Method method) {
|
||||
super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
||||
response.finishFuture(paramHandlerResultType, future);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.test.sncp;
|
||||
|
||||
import org.redkale.annotation.ResourceType;
|
||||
|
||||
/** @author zhangjx */
|
||||
@ResourceType(SncpTestIService.class)
|
||||
public class _DynLocalSncpTestService extends SncpTestServiceImpl {}
|
||||
@@ -9,9 +9,9 @@ import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.ConvertColumn;
|
||||
import org.redkale.convert.Reader;
|
||||
import org.redkale.convert.Writer;
|
||||
import org.redkale.net.sncp.SncpActionServlet;
|
||||
import org.redkale.net.sncp.SncpRequest;
|
||||
import org.redkale.net.sncp.SncpResponse;
|
||||
import org.redkale.net.sncp.SncpServlet.SncpActionServlet;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.test.util.TestBean;
|
||||
import org.redkale.util.Uint128;
|
||||
@@ -36,7 +36,7 @@ public class DynActionTestService_change extends SncpActionServlet {
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
DynActionTestService_change_paramBean bean = convert.convertFrom(paramComposeType, in);
|
||||
DynActionTestService_change_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
Object rs = serviceObj.change(bean.arg1, bean.arg2, bean.arg3);
|
||||
response.finish(boolean.class, rs);
|
||||
|
||||
@@ -10,9 +10,9 @@ import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.ConvertColumn;
|
||||
import org.redkale.convert.Reader;
|
||||
import org.redkale.convert.Writer;
|
||||
import org.redkale.net.sncp.SncpActionServlet;
|
||||
import org.redkale.net.sncp.SncpRequest;
|
||||
import org.redkale.net.sncp.SncpResponse;
|
||||
import org.redkale.net.sncp.SncpServlet.SncpActionServlet;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.test.util.TestBean;
|
||||
import org.redkale.util.Uint128;
|
||||
@@ -37,7 +37,7 @@ public class DynActionTestService_changeName extends SncpActionServlet {
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
DynActionTestService_changeName_paramBean bean = convert.convertFrom(paramComposeType, in);
|
||||
DynActionTestService_changeName_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
CompletableFuture future = serviceObj.changeName(bean.arg1, bean.arg2, bean.arg3);
|
||||
response.finishFuture(paramHandlerResultType, future);
|
||||
|
||||
@@ -8,9 +8,9 @@ import java.lang.reflect.Method;
|
||||
import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.Reader;
|
||||
import org.redkale.convert.Writer;
|
||||
import org.redkale.net.sncp.SncpActionServlet;
|
||||
import org.redkale.net.sncp.SncpRequest;
|
||||
import org.redkale.net.sncp.SncpResponse;
|
||||
import org.redkale.net.sncp.SncpServlet;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.test.util.TestBean;
|
||||
import org.redkale.util.Uint128;
|
||||
@@ -19,7 +19,7 @@ import org.redkale.util.Uint128;
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class DynActionTestService_hello extends SncpServlet.SncpActionServlet {
|
||||
public class DynActionTestService_hello extends SncpActionServlet {
|
||||
|
||||
public DynActionTestService_hello(
|
||||
String resourceName,
|
||||
@@ -35,7 +35,7 @@ public class DynActionTestService_hello extends SncpServlet.SncpActionServlet {
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
TestBean bean = convert.convertFrom(paramComposeType, in);
|
||||
TestBean bean = convert.convertFrom(paramComposeBeanType, in);
|
||||
TestService serviceObj = (TestService) service();
|
||||
serviceObj.hello(bean);
|
||||
response.finishVoid();
|
||||
|
||||
@@ -9,9 +9,9 @@ import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.ConvertColumn;
|
||||
import org.redkale.convert.Reader;
|
||||
import org.redkale.convert.Writer;
|
||||
import org.redkale.net.sncp.SncpActionServlet;
|
||||
import org.redkale.net.sncp.SncpRequest;
|
||||
import org.redkale.net.sncp.SncpResponse;
|
||||
import org.redkale.net.sncp.SncpServlet.SncpActionServlet;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.test.util.TestBean;
|
||||
import org.redkale.util.Uint128;
|
||||
@@ -36,7 +36,7 @@ public class DynActionTestService_insert extends SncpActionServlet {
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
DynActionTestService_insert_paramBean bean = convert.convertFrom(paramComposeType, in);
|
||||
DynActionTestService_insert_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
||||
bean.arg0 = response.getParamAsyncHandler();
|
||||
TestService serviceObj = (TestService) service();
|
||||
serviceObj.insert(bean.arg0, bean.arg1, bean.arg2, bean.arg3);
|
||||
|
||||
@@ -10,9 +10,9 @@ import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.ConvertColumn;
|
||||
import org.redkale.convert.Reader;
|
||||
import org.redkale.convert.Writer;
|
||||
import org.redkale.net.sncp.SncpActionServlet;
|
||||
import org.redkale.net.sncp.SncpRequest;
|
||||
import org.redkale.net.sncp.SncpResponse;
|
||||
import org.redkale.net.sncp.SncpServlet.SncpActionServlet;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.test.util.TestBean;
|
||||
import org.redkale.util.Uint128;
|
||||
@@ -37,7 +37,7 @@ public class DynActionTestService_update extends SncpActionServlet {
|
||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
Convert<Reader, Writer> convert = request.getConvert();
|
||||
Reader in = request.getReader();
|
||||
DynActionTestService_update_paramBean bean = convert.convertFrom(paramComposeType, in);
|
||||
DynActionTestService_update_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
||||
bean.arg3 = response.getParamAsyncHandler();
|
||||
TestService serviceObj = (TestService) service();
|
||||
serviceObj.update(bean.arg1, bean.arg2, bean.arg3, bean.arg4, bean.arg5, bean.arg6);
|
||||
@@ -75,4 +75,4 @@ public class DynActionTestService_update extends SncpActionServlet {
|
||||
@ConvertColumn(index = 6)
|
||||
public int arg6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user