diff --git a/src/main/java/org/redkale/asm/AsmMethodBean.java b/src/main/java/org/redkale/asm/AsmMethodBean.java index 0f6699803..6368d828e 100644 --- a/src/main/java/org/redkale/asm/AsmMethodBean.java +++ b/src/main/java/org/redkale/asm/AsmMethodBean.java @@ -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 + '}'; } } diff --git a/src/main/java/org/redkale/asm/AsmMethodParam.java b/src/main/java/org/redkale/asm/AsmMethodParam.java index d5ab67c50..5790173a9 100644 --- a/src/main/java/org/redkale/asm/AsmMethodParam.java +++ b/src/main/java/org/redkale/asm/AsmMethodParam.java @@ -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 + '}'; } } diff --git a/src/main/java/org/redkale/net/sncp/Sncp.java b/src/main/java/org/redkale/net/sncp/Sncp.java index 245f1c11e..e1bc96eb8 100644 --- a/src/main/java/org/redkale/net/sncp/Sncp.java +++ b/src/main/java/org/redkale/net/sncp/Sncp.java @@ -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; diff --git a/src/main/java/org/redkale/net/sncp/SncpActionServlet.java b/src/main/java/org/redkale/net/sncp/SncpActionServlet.java new file mode 100644 index 000000000..392bbc79c --- /dev/null +++ b/src/main/java/org/redkale/net/sncp/SncpActionServlet.java @@ -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对象 + * + *

详情见: 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 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 service() { + return (T) service; + } + + @Override + public Uint128 getServiceid() { + return serviceid; + } + + public Uint128 getActionid() { + return actionid; + } + + public String actionName() { + return method.getDeclaringClass().getSimpleName() + "." + method.getName(); + } + + /** + * + * + *

+ * + *
+     * 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);
+     *     }
+     * }
+     *
+     * 
+ * + *
+ * + * @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, + "", + "(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, + "", + "(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); // 不可能会发生 + } + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpRemoteAction.java b/src/main/java/org/redkale/net/sncp/SncpRemoteAction.java new file mode 100644 index 000000000..fe2f03111 --- /dev/null +++ b/src/main/java/org/redkale/net/sncp/SncpRemoteAction.java @@ -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方法的相关信息对象 + * + *

详情见: 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 paramHandlerClass; // CompletionHandler参数的类型 + + protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型 + + protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型 + + protected final Class returnFutureClass; // 返回结果的CompletableFuture类型 + + protected final Creator 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 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 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, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // 带参数构造函数 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "([Ljava/lang/Object;)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()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; + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java b/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java index 6dfa6c981..1829b659c 100644 --- a/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java +++ b/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java @@ -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 { public Set 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 paramHandlerClass; // CompletionHandler参数的类型 - - protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型 - - protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型 - - protected final Class returnFutureClass; // 返回结果的CompletableFuture类型 - - protected final Creator 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()) + "}"; - } - } } diff --git a/src/main/java/org/redkale/net/sncp/SncpResponse.java b/src/main/java/org/redkale/net/sncp/SncpResponse.java index 474e5f0cd..80df56f9f 100644 --- a/src/main/java/org/redkale/net/sncp/SncpResponse.java +++ b/src/main/java/org/redkale/net/sncp/SncpResponse.java @@ -139,6 +139,7 @@ public class SncpResponse extends Response { 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 { finish(0, out); } + @ClassDepends public final void finishFuture(final Type futureResultType, final Future future) { if (future == null) { finishVoid(); diff --git a/src/main/java/org/redkale/net/sncp/SncpServlet.java b/src/main/java/org/redkale/net/sncp/SncpServlet.java index 663c82706..787cbc276 100644 --- a/src/main/java/org/redkale/net/sncp/SncpServlet.java +++ b/src/main/java/org/redkale/net/sncp/SncpServlet.java @@ -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 private final HashMap 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 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 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 service() { - return (T) service; - } - - @Override - public Uint128 getServiceid() { - return serviceid; - } - - public Uint128 getActionid() { - return actionid; - } - - public String actionName() { - return method.getDeclaringClass().getSimpleName() + "." + method.getName(); - } - - /** - * - * - *

- * - *
-         * 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);
-         *     }
-         * }
-         *
-         * 
- * - *
- * - * @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, - "", - "(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, - "", - "(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); // 不可能会发生 - } - } - } } diff --git a/src/main/java/org/redkale/util/Creator.java b/src/main/java/org/redkale/util/Creator.java index fd4de1c43..5c3be916c 100644 --- a/src/main/java/org/redkale/util/Creator.java +++ b/src/main/java/org/redkale/util/Creator.java @@ -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 { 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 { { // 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 { 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 { { 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()) { diff --git a/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java b/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java index 1c47f0012..be640a249 100644 --- a/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java @@ -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(); } diff --git a/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java b/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java index 03fea76ff..70410f028 100644 --- a/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java @@ -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 diff --git a/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java b/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java index 6262438ce..a37d6b6a2 100644 --- a/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpRequestParseTest.java @@ -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(); } diff --git a/src/test/java/org/redkale/test/sncp/SncpSleepTest.java b/src/test/java/org/redkale/test/sncp/SncpSleepTest.java index c07a2147f..fda04693f 100644 --- a/src/test/java/org/redkale/test/sncp/SncpSleepTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpSleepTest.java @@ -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); diff --git a/src/test/java/org/redkale/test/sncp/TestService.java b/src/test/java/org/redkale/test/sncp/TestService.java deleted file mode 100644 index 927749c0c..000000000 --- a/src/test/java/org/redkale/test/sncp/TestService.java +++ /dev/null @@ -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 handler, TestBean bean, String name, int id); - - public CompletableFuture 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 handler, TestBean bean, String name, int id) {} - - @Override - public CompletableFuture changeName(TestBean bean, String name, int id) { - return null; - } -} - -class BooleanHandler implements CompletionHandler { - - @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 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 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 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 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); - } -} diff --git a/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java b/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java deleted file mode 100644 index 1a97b4cf7..000000000 --- a/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java +++ /dev/null @@ -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 {} diff --git a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_change.java b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_change.java index d66c6017e..11c051744 100644 --- a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_change.java +++ b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_change.java @@ -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 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); diff --git a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_changeName.java b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_changeName.java index dd8345246..4b1f0a93a 100644 --- a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_changeName.java +++ b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_changeName.java @@ -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 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); diff --git a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_hello.java b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_hello.java index ed063fa2e..d6838b0f6 100644 --- a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_hello.java +++ b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_hello.java @@ -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 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(); diff --git a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_insert.java b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_insert.java index 8cd403f20..25fd85ac6 100644 --- a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_insert.java +++ b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_insert.java @@ -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 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); diff --git a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_update.java b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_update.java index 2d18ef30d..0f927caa8 100644 --- a/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_update.java +++ b/src/test/java/org/redkale/test/sncp/dyn/DynActionTestService_update.java @@ -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 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; } - } \ No newline at end of file +}