diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java index 3e92beb77..38915f118 100644 --- a/src/main/java/org/redkale/boot/Application.java +++ b/src/main/java/org/redkale/boot/Application.java @@ -942,7 +942,7 @@ public final class Application { }); } if (!compileMode) { - properties.put(SncpOldClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName()); + properties.put(OldSncpClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName()); } } if (compileMode) { diff --git a/src/main/java/org/redkale/boot/NodeServer.java b/src/main/java/org/redkale/boot/NodeServer.java index 829919b41..064a4bf77 100644 --- a/src/main/java/org/redkale/boot/NodeServer.java +++ b/src/main/java/org/redkale/boot/NodeServer.java @@ -291,7 +291,7 @@ public abstract class NodeServer { } //ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory); - SncpOldClient client = srcObj instanceof Service ? Sncp.getSncpOldClient((Service) srcObj) : null; + OldSncpClient client = srcObj instanceof Service ? Sncp.getSncpOldClient((Service) srcObj) : null; final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); final Set groups = new HashSet<>(); Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, null, appResFactory, appSncpTranFactory, sncpAddr, groups, null); @@ -343,7 +343,7 @@ public abstract class NodeServer { throw new RedkaleException("CacheSource must be inject in Service, cannot in " + srcObj); } final Service srcService = (Service) srcObj; - SncpOldClient client = Sncp.getSncpOldClient(srcService); + OldSncpClient client = Sncp.getSncpOldClient(srcService); final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); //final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService) && sncpAddr != null; //不配置SNCP服务会导致ws=false时没有注入CacheMemorySource final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService); diff --git a/src/main/java/org/redkale/boot/NodeSncpServer.java b/src/main/java/org/redkale/boot/NodeSncpServer.java index a4f625b0d..8950aa05e 100644 --- a/src/main/java/org/redkale/boot/NodeSncpServer.java +++ b/src/main/java/org/redkale/boot/NodeSncpServer.java @@ -126,7 +126,7 @@ public class NodeSncpServer extends NodeServer { @Override protected void loadServlet(ClassFilter servletFilter, ClassFilter otherFilter) throws Exception { RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName()); - RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName()); + RedkaleClassLoader.putReflectionPublicClasses(OldSncpDynServlet.class.getName()); } @Override diff --git a/src/main/java/org/redkale/boot/watch/TransportWatchService.java b/src/main/java/org/redkale/boot/watch/TransportWatchService.java index dea20c12c..a21d4053b 100644 --- a/src/main/java/org/redkale/boot/watch/TransportWatchService.java +++ b/src/main/java/org/redkale/boot/watch/TransportWatchService.java @@ -75,7 +75,7 @@ public class TransportWatchService extends AbstractWatchService { if (!Sncp.isSncpDyn(service)) { continue; } - SncpOldClient client = Sncp.getSncpOldClient(service); + OldSncpClient client = Sncp.getSncpOldClient(service); if (Sncp.isRemote(service)) { if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { client.getRemoteGroupTransport().addRemoteAddresses(address); @@ -117,7 +117,7 @@ public class TransportWatchService extends AbstractWatchService { if (!Sncp.isSncpDyn(service)) { continue; } - SncpOldClient client = Sncp.getSncpOldClient(service); + OldSncpClient client = Sncp.getSncpOldClient(service); if (Sncp.isRemote(service)) { if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { client.getRemoteGroupTransport().removeRemoteAddresses(address); diff --git a/src/main/java/org/redkale/convert/bson/BsonReader.java b/src/main/java/org/redkale/convert/bson/BsonReader.java index 11940d346..136a8f5a7 100644 --- a/src/main/java/org/redkale/convert/bson/BsonReader.java +++ b/src/main/java/org/redkale/convert/bson/BsonReader.java @@ -55,15 +55,16 @@ public class BsonReader extends Reader { setBytes(bytes, start, len); } - public final void setBytes(byte[] bytes) { + public final BsonReader setBytes(byte[] bytes) { if (bytes == null) { this.position = 0; } else { setBytes(bytes, 0, bytes.length); } + return this; } - public final void setBytes(byte[] bytes, int start, int len) { + public final BsonReader setBytes(byte[] bytes, int start, int len) { if (bytes == null) { this.position = 0; } else { @@ -71,6 +72,7 @@ public class BsonReader extends Reader { this.position = start - 1; //this.limit = start + len - 1; } + return this; } protected boolean recycle() { @@ -81,8 +83,9 @@ public class BsonReader extends Reader { return true; } - public void close() { - this.recycle(); + public BsonReader clear() { + recycle(); + return this; } /** diff --git a/src/main/java/org/redkale/convert/bson/BsonWriter.java b/src/main/java/org/redkale/convert/bson/BsonWriter.java index d393fdba3..5079cea02 100644 --- a/src/main/java/org/redkale/convert/bson/BsonWriter.java +++ b/src/main/java/org/redkale/convert/bson/BsonWriter.java @@ -166,6 +166,11 @@ public class BsonWriter extends Writer implements ByteTuple { return true; } + public BsonWriter clear() { + recycle(); + return this; + } + @Override public String toString() { return this.getClass().getSimpleName() + "[count=" + this.count + "]"; diff --git a/src/main/java/org/redkale/mq/SncpMessageRequest.java b/src/main/java/org/redkale/mq/SncpMessageRequest.java index 65b8a6cd1..5ae09cb8d 100644 --- a/src/main/java/org/redkale/mq/SncpMessageRequest.java +++ b/src/main/java/org/redkale/mq/SncpMessageRequest.java @@ -6,9 +6,7 @@ package org.redkale.mq; import java.nio.ByteBuffer; -import java.util.logging.*; import org.redkale.net.sncp.*; -import org.redkale.util.Utility; /** * @@ -31,16 +29,5 @@ public class SncpMessageRequest extends SncpRequest { this.createTime = System.currentTimeMillis(); readHeader(ByteBuffer.wrap(message.getContent()), null); } - - @Override //被SncpAsyncHandler.sncp_setParams调用 - protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) { - if (message.localAttach != null) { - return; - } - if (logger.isLoggable(Level.FINER)) { - message.attach(Utility.append(new Object[]{action.actionName()}, params)); - } else { - message.attach(params); - } - } + } diff --git a/src/main/java/org/redkale/net/sncp/SncpOldClient.java b/src/main/java/org/redkale/net/sncp/OldSncpClient.java similarity index 98% rename from src/main/java/org/redkale/net/sncp/SncpOldClient.java rename to src/main/java/org/redkale/net/sncp/OldSncpClient.java index 852937cca..5bc8fee3f 100644 --- a/src/main/java/org/redkale/net/sncp/SncpOldClient.java +++ b/src/main/java/org/redkale/net/sncp/OldSncpClient.java @@ -31,9 +31,9 @@ import org.redkale.util.*; * * @author zhangjx */ -public final class SncpOldClient { +public final class OldSncpClient { - protected static final Logger logger = Logger.getLogger(SncpOldClient.class.getSimpleName()); + protected static final Logger logger = Logger.getLogger(OldSncpClient.class.getSimpleName()); protected final JsonConvert convert = JsonFactory.root().getConvert(); @@ -70,7 +70,7 @@ public final class SncpOldClient { //远程模式, 可能为null protected Transport remoteGroupTransport; - public SncpOldClient(final String serviceResourceName, final Class serviceTypeOrImplClass, final T service, MessageAgent messageAgent, final TransportFactory factory, + public OldSncpClient(final String serviceResourceName, final Class serviceTypeOrImplClass, final T service, MessageAgent messageAgent, final TransportFactory factory, final boolean remote, final Class serviceClass, final InetSocketAddress clientSncpAddress) { this.remote = remote; this.messageAgent = messageAgent; @@ -202,7 +202,7 @@ public final class SncpOldClient { final Attribute attr = action.paramAttrs[i]; attr.set(params[i - 1], bsonConvert.convertFrom(attr.genericType(), reader)); } - return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader); + return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.returnObjectType, reader); } catch (RpcRemoteException re) { throw re; } catch (TimeoutException e) { @@ -376,7 +376,7 @@ public final class SncpOldClient { final Attribute attr = action.paramAttrs[i]; attr.set(params[i - 1], bsonConvert.convertFrom(attr.genericType(), reader)); } - Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader); + Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.returnObjectType, reader); handler.completed(rs, handlerAttach); } catch (Exception e) { handler.failed(e, handlerAttach); diff --git a/src/main/java/org/redkale/net/sncp/OldSncpDynServlet.java b/src/main/java/org/redkale/net/sncp/OldSncpDynServlet.java new file mode 100644 index 000000000..8e138a3a4 --- /dev/null +++ b/src/main/java/org/redkale/net/sncp/OldSncpDynServlet.java @@ -0,0 +1,727 @@ +/* + * 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.net.sncp; + +import java.io.IOException; +import java.lang.reflect.*; +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.*; +import org.redkale.annotation.*; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import org.redkale.asm.*; +import static org.redkale.asm.Opcodes.*; +import org.redkale.asm.Type; +import org.redkale.convert.bson.*; +import org.redkale.net.sncp.OldSncpHandler.DefaultSncpAsyncHandler; +import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + *
+         *  public class TestService implements Service {
+         *
+         *      public boolean change(TestBean bean, String name, int id) {
+         *          return false;
+         *      }
+         *
+         *      public void insert(CompletionHandler<Boolean, TestBean> 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) {
+         *          return null;
+         *      }
+         * }
+         *
+         *
+         * class DynActionTestService_change extends SncpServletAction {
+         *
+         *      public TestService service;
+         *
+         *      @Override
+      public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
+          TestBean arg1 = convert.convertFrom(paramTypes[1], in);
+          String arg2 = convert.convertFrom(paramTypes[2], in);
+          int arg3 = convert.convertFrom(paramTypes[3], in);
+          Object rs = service.change(arg1, arg2, arg3);
+          _callParameter(out, arg1, arg2, arg3);
+          convert.convertTo(out, paramTypes[0], rs);
+      }
+ }
+
+ class DynActionTestService_insert extends SncpServletAction {
+
+      public TestService service;
+
+      @Override
+      public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
+          OldSncpHandler arg0 = handler;
+          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);
+          handler.sncp_setParams(arg0, arg1, arg2, arg3);
+          service.insert(arg0, arg1, arg2, arg3);
+       }
+ }
+
+ class DynActionTestService_update extends SncpServletAction {
+
+      public TestService service;
+
+      @Override
+      public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
+          long a1 = convert.convertFrom(paramTypes[1], in);
+          short a2 = convert.convertFrom(paramTypes[2], in);
+          OldSncpHandler a3 = handler;
+          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);
+          handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
+          service.update(a1, a2, a3, arg1, arg2, arg3);
+      }
+ }
+
+
+ class DynActionTestService_changeName extends SncpServletAction {
+
+      public TestService service;
+
+      @Override
+      public void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable {
+          TestBean arg1 = convert.convertFrom(paramTypes[1], in);
+          String arg2 = convert.convertFrom(paramTypes[2], in);
+          int arg3 = convert.convertFrom(paramTypes[3], in);
+          handler.sncp_setParams(arg1, arg2, arg3);
+          CompletableFuture future = service.changeName(arg1, arg2, arg3);
+          handler.sncp_setFuture(future);
+      }
+ }
+
+ 
+ */ +public final class OldSncpDynServlet extends SncpServlet { + + private final AtomicInteger maxTypeLength; + + private final AtomicInteger maxNameLength; + + private static final Logger logger = Logger.getLogger(OldSncpDynServlet.class.getSimpleName()); + + private final Uint128 serviceid; + + private final HashMap actions = new HashMap<>(); + + public OldSncpDynServlet(final BsonConvert convert, final String serviceResourceName, final Class serviceResourceType, final Service service, + final AtomicInteger maxTypeLength, AtomicInteger maxNameLength) { + super(serviceResourceName, serviceResourceType, service); + this.maxTypeLength = maxTypeLength; + this.maxNameLength = maxNameLength; + this.serviceid = Sncp.serviceid(serviceResourceName, serviceResourceType); + RedkaleClassLoader.putReflectionPublicMethods(service.getClass().getName()); + for (Map.Entry en : Sncp.loadMethodActions(serviceResourceType).entrySet()) { + SncpServletAction action; + try { + action = SncpServletAction.create(service, serviceid, en.getKey(), en.getValue()); + } catch (RuntimeException e) { + throw new SncpException(en.getValue() + " create " + SncpServletAction.class.getSimpleName() + " error", e); + } + action.convert = convert; + actions.put(en.getKey(), action); + } + maxNameLength.set(Math.max(maxNameLength.get(), serviceResourceName.length() + 1)); + maxTypeLength.set(Math.max(maxTypeLength.get(), serviceType.getName().length())); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getSimpleName()).append(" (type=").append(serviceType.getName()); + int len = this.maxTypeLength.get() - serviceType.getName().length(); + for (int i = 0; i < len; i++) { + sb.append(' '); + } + sb.append(", serviceid=").append(serviceid).append(", name='").append(serviceName).append("'"); + for (int i = 0; i < this.maxNameLength.get() - serviceName.length(); i++) { + sb.append(' '); + } + sb.append(", actions.size=").append(actions.size() > 9 ? "" : " ").append(actions.size()).append(")"); + return sb.toString(); + } + + @Override + public Uint128 getServiceid() { + return serviceid; + } + + @Override + public int compareTo(SncpServlet other) { + if (!(other instanceof OldSncpDynServlet)) { + return 1; + } + OldSncpDynServlet o = (OldSncpDynServlet) other; + int rs = this.serviceType.getName().compareTo(o.serviceType.getName()); + if (rs == 0) { + rs = this.serviceName.compareTo(o.serviceName); + } + return rs; + } + + @Override + @SuppressWarnings("unchecked") + public void execute(SncpRequest request, SncpResponse response) throws IOException { + final SncpServletAction action = actions.get(request.getHeader().getActionid()); + //logger.log(Level.FINEST, "sncpdyn.execute: " + request + ", " + (action == null ? "null" : action.method)); + if (action == null) { + response.finish(SncpResponse.RETCODE_ILLACTIONID, null); //无效actionid + } else { + BsonWriter out = action.convert.pollBsonWriter(); + out.writePlaceholderTo(HEADER_SIZE); + BsonReader in = action.convert.pollBsonReader(); + OldSncpHandler handler = null; + try { + if (action.handlerFuncParamIndex >= 0) { + if (action.handlerFuncParamType == CompletionHandler.class) { + handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response); + } else { + Creator creator = action.handlerCreator; + if (creator == null) { + creator = OldSncpHandler.Factory.createCreator(action.handlerFuncParamType); + action.handlerCreator = creator; + } + handler = creator.create(new DefaultSncpAsyncHandler(logger, action, in, out, request, response)); + } + } else if (action.boolReturnTypeFuture) { + handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response); + } + in.setBytes(request.getBody()); + action.action(in, out, handler); + if (handler == null) { + response.finish(0, out); + action.convert.offerBsonReader(in); + action.convert.offerBsonWriter(out); + } else if (action.boolReturnTypeFuture) { + CompletableFuture future = handler.sncp_getFuture(); + if (future == null) { + action._callParameter(out, handler.sncp_getParams()); + action.convert.convertTo(out, Object.class, null); + } else { + Object[] sncpParams = handler.sncp_getParams(); + future.whenComplete((v, e) -> { + if (e != null) { + response.getContext().getLogger().log(Level.SEVERE, "sncp CompleteAsync error(" + request + ")", e); + response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); + return; + } + action._callParameter(out, sncpParams); + action.convert.convertTo(out, Object.class, v); + response.finish(0, out); + action.convert.offerBsonReader(in); + action.convert.offerBsonWriter(out); + }); + } + } + } catch (Throwable t) { + response.getContext().getLogger().log(Level.SEVERE, "sncp execute error(" + request + ")", t); + response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); + } + } + } + + public static abstract class SncpServletAction { + + public Method method; + + public Creator handlerCreator; + + protected boolean nonBlocking; + + @Resource + protected BsonConvert convert; + + protected org.redkale.util.Attribute[] paramAttrs; // 为null表示无RpcCall处理,index=0固定为null, 其他为参数标记的RpcCall回调方法 + + protected java.lang.reflect.Type[] paramTypes; //index=0表示返回参数的type, void的返回参数类型为null + + protected int handlerFuncParamIndex = -1; //handlerFuncParamIndex>=0表示存在CompletionHandler参数 + + protected Class handlerFuncParamType; //CompletionHandler参数的类型 + + protected boolean boolReturnTypeFuture = false; // 返回结果类型是否为 CompletableFuture + + public abstract void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable; + + //只有同步方法才调用 (没有CompletionHandler、CompletableFuture) + public final void _callParameter(final BsonWriter out, final Object... params) { + if (paramAttrs != null) { + for (int i = 1; i < paramAttrs.length; i++) { + org.redkale.util.Attribute attr = paramAttrs[i]; + if (attr == null) { + continue; + } + out.writeByte((byte) i); + convert.convertTo(out, attr.genericType(), attr.get(params[i - 1])); + } + } + out.writeByte((byte) 0); + } + + public String actionName() { + return method.getDeclaringClass().getSimpleName() + "." + method.getName(); + } + + /** + *
+         *  public class TestService implements Service {
+         *
+         *      public boolean change(TestBean bean, String name, int id) {
+         *          return false;
+         *      }
+         *
+         *      public void insert(CompletionHandler<Boolean, TestBean> 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) {
+         *          return null;
+         *      }
+         * }
+         *
+         *
+         * class DynActionTestService_change extends SncpServletAction {
+         *
+         *      public TestService service;
+         *
+         *      @Override
+      public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
+          TestBean arg1 = convert.convertFrom(paramTypes[1], in);
+          String arg2 = convert.convertFrom(paramTypes[2], in);
+          int arg3 = convert.convertFrom(paramTypes[3], in);
+          Object rs = service.change(arg1, arg2, arg3);
+          _callParameter(out, arg1, arg2, arg3);
+          convert.convertTo(out, paramTypes[0], rs);
+      }
+ }
+
+ class DynActionTestService_insert extends SncpServletAction {
+
+      public TestService service;
+
+      @Override
+      public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
+          OldSncpHandler arg0 = handler;
+          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);
+          handler.sncp_setParams(arg0, arg1, arg2, arg3);
+          service.insert(arg0, arg1, arg2, arg3);
+       }
+ }
+
+ class DynActionTestService_update extends SncpServletAction {
+
+      public TestService service;
+
+      @Override
+      public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable {
+          long a1 = convert.convertFrom(paramTypes[1], in);
+          short a2 = convert.convertFrom(paramTypes[2], in);
+          OldSncpHandler a3 = handler;
+          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);
+          handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
+          service.update(a1, a2, a3, arg1, arg2, arg3);
+      }
+ }
+
+
+ class DynActionTestService_changeName extends SncpServletAction {
+
+      public TestService service;
+
+      @Override
+      public void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable {
+          TestBean arg1 = convert.convertFrom(paramTypes[1], in);
+          String arg2 = convert.convertFrom(paramTypes[2], in);
+          int arg3 = convert.convertFrom(paramTypes[3], in);
+          handler.sncp_setParams(arg1, arg2, arg3);
+          CompletableFuture future = service.changeName(arg1, arg2, arg3);
+          handler.sncp_setFuture(future);
+      }
+ }
+
+ 
+ * + * @param service Service + * @param serviceid 类ID + * @param actionid 操作ID + * @param method 方法 + * + * @return SncpServletAction + */ + @SuppressWarnings("unchecked") + public static SncpServletAction create(final Service service, final Uint128 serviceid, final Uint128 actionid, final Method method) { + final Class serviceClass = service.getClass(); + final String supDynName = SncpServletAction.class.getName().replace('.', '/'); + final String serviceName = serviceClass.getName().replace('.', '/'); + final String convertName = BsonConvert.class.getName().replace('.', '/'); + final String handlerName = OldSncpHandler.class.getName().replace('.', '/'); + final String asyncHandlerDesc = Type.getDescriptor(OldSncpHandler.class); + final String convertReaderDesc = Type.getDescriptor(BsonReader.class); + final String convertWriterDesc = Type.getDescriptor(BsonWriter.class); + final String serviceDesc = Type.getDescriptor(serviceClass); + final boolean boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType()); + final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + serviceClass.getName().replace('.', '_').replace('$', '_') + "__" + method.getName() + "__" + actionid; + + int handlerFuncIndex = -1; + Class handlerFuncType = null; + Class newClazz = null; + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; + final Class[] paramClasses = method.getParameterTypes(); + for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数 + if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) { + handlerFuncIndex = i; + handlerFuncType = paramClasses[i]; + break; + } + } + } catch (Throwable ex) { + } + + 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); + FieldVisitor fv; + MethodDebugVisitor mv; + + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null); + { + { + fv = cw.visitField(ACC_PUBLIC, "service", serviceDesc, null, null); + fv.visitEnd(); + } + fv.visitEnd(); + } + { // constructor方法 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + String convertFromDesc = "(Ljava/lang/reflect/Type;" + convertReaderDesc + ")Ljava/lang/Object;"; + try { + convertFromDesc = Type.getMethodDescriptor(BsonConvert.class.getMethod("convertFrom", java.lang.reflect.Type.class, BsonReader.class)); + } catch (Exception ex) { + throw new SncpException(ex); //不可能会发生 + } + { // action方法 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + asyncHandlerDesc + ")V", null, new String[]{"java/lang/Throwable"})); + //mv.setDebug(true); + int iconst = ICONST_1; + int intconst = 1; + int store = 4; //action的参数个数+1 + final Class[] paramClasses = method.getParameterTypes(); + int[][] codes = new int[paramClasses.length][2]; + 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; + handlerFuncType = paramClasses[i]; + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/')); + mv.visitVarInsn(ASTORE, store); + codes[i] = new int[]{ALOAD, store}; + store++; + iconst++; + intconst++; + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); + mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class))); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); + mv.visitInsn(POP); + continue; + } + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); + 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, 1); + + 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++; + } + if (boolReturnTypeFuture || handlerFuncIndex >= 0) { //调用SncpAsyncHandler.setParams(Object... params) + mv.visitVarInsn(ALOAD, 3); + if (paramClasses.length < 6) { + mv.visitInsn(ICONST_0 + paramClasses.length); + } else if (paramClasses.length <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, paramClasses.length); + } else if (paramClasses.length <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, paramClasses.length); + } else { + mv.visitLdcInsn(paramClasses.length); + } + + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + int insn = 3; //action的参数个数 + for (int j = 0; j < paramClasses.length; j++) { + final Class pt = paramClasses[j]; + mv.visitInsn(DUP); + insn++; + if (j < 6) { + mv.visitInsn(ICONST_0 + j); + } else if (j <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, j); + } else if (j <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, j); + } else { + mv.visitLdcInsn(j); + } + if (pt.isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + Class bigclaz = TypeToken.primitiveToWrapper(pt); + mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false); + } else { + mv.visitVarInsn(ALOAD, insn); + } + mv.visitInsn(AASTORE); + } + mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true); + } + { //调用service + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "service", serviceDesc); + for (int[] j : codes) { + mv.visitVarInsn(j[0], j[1]); + } + mv.visitMethodInsn(INVOKEVIRTUAL, serviceName, method.getName(), Type.getMethodDescriptor(method), false); + } + + final Class returnClass = method.getReturnType(); + if (returnClass != void.class) { + 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) { + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, store); + mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setFuture", "(Ljava/util/concurrent/CompletableFuture;)V", true); + } + } + if (!boolReturnTypeFuture && handlerFuncIndex < 0) { //同步方法 + //------------------------- _callParameter 方法 -------------------------------- + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 2); + if (paramClasses.length < 6) { //参数总数量 + mv.visitInsn(ICONST_0 + paramClasses.length); + } else if (paramClasses.length <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, paramClasses.length); + } else if (paramClasses.length <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, paramClasses.length); + } else { + mv.visitLdcInsn(paramClasses.length); + } + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + int insn = 3;//action的参数个数 + for (int j = 0; j < paramClasses.length; j++) { + final Class pt = paramClasses[j]; + mv.visitInsn(DUP); + insn++; + if (j < 6) { + mv.visitInsn(ICONST_0 + j); + } else if (j <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, j); + } else if (j <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, j); + } else { + mv.visitLdcInsn(j); + } + if (pt.isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + Class bigclaz = TypeToken.primitiveToWrapper(pt); + mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false); + } else { + mv.visitVarInsn(ALOAD, insn); + } + mv.visitInsn(AASTORE); + } + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false); + } + //-------------------------直接返回 或者 调用convertTo方法 -------------------------------- + int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1; + if (boolReturnTypeFuture || returnClass == void.class) { //返回 + mv.visitInsn(RETURN); + maxStack = 8; + } else { //同步方法调用 + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;"); + mv.visitInsn(ICONST_0); + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, store); + mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertTo", "(" + convertWriterDesc + "Ljava/lang/reflect/Type;Ljava/lang/Object;)V", false); + mv.visitInsn(RETURN); + store++; + } + mv.visitMaxs(maxStack, 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) { + } + for (java.lang.reflect.Type t : originalParamTypes) { + if (t.toString().startsWith("java.lang.")) { + continue; + } + BsonFactory.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) { + BsonFactory.root().loadEncoder(t); + } + } else { + try { + BsonFactory.root().loadEncoder(originalReturnType); + } catch (Exception e) { + System.err.println(method); + } + } + } + } + NonBlocking non = method.getAnnotation(NonBlocking.class); + if (non == null) { + non = service.getClass().getAnnotation(NonBlocking.class); + } + try { + SncpServletAction instance = (SncpServletAction) newClazz.getDeclaredConstructor().newInstance(); + instance.method = method; + instance.nonBlocking = non == null ? false : non.value(); + java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1]; + types[0] = originalReturnType; + System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length); + instance.paramTypes = types; + instance.handlerFuncParamIndex = handlerFuncIndex; + instance.handlerFuncParamType = handlerFuncType; + instance.boolReturnTypeFuture = boolReturnTypeFuture; + newClazz.getField("service").set(instance, service); + return instance; + } catch (Exception ex) { + throw new SncpException(ex); //不可能会发生 + } + } + } + +} diff --git a/src/main/java/org/redkale/net/sncp/OldSncpHandler.java b/src/main/java/org/redkale/net/sncp/OldSncpHandler.java new file mode 100644 index 000000000..b0df6e21b --- /dev/null +++ b/src/main/java/org/redkale/net/sncp/OldSncpHandler.java @@ -0,0 +1,321 @@ +/* + * 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.net.sncp; + +import java.nio.channels.CompletionHandler; +import java.util.concurrent.CompletableFuture; +import java.util.logging.*; +import org.redkale.annotation.ConstructorParameters; +import org.redkale.asm.*; +import static org.redkale.asm.Opcodes.*; +import org.redkale.convert.bson.*; +import org.redkale.net.sncp.OldSncpDynServlet.SncpServletAction; +import org.redkale.util.*; + +/** + * 异步回调函数
+ * + * public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler + * + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @param 结果对象的泛型 + * @param 附件对象的泛型 + */ +public interface OldSncpHandler extends CompletionHandler { + + public Object[] sncp_getParams(); + + public void sncp_setParams(Object... params); + + public void sncp_setFuture(CompletableFuture future); + + public CompletableFuture sncp_getFuture(); + + static class Factory { + + /** + *

+
+ 考虑点:
+      1、CompletionHandler子类是接口,且还有其他多个方法
+      2、CompletionHandler子类是类, 需要继承,且必须有空参数构造函数
+      3、CompletionHandler子类无论是接口还是类,都可能存在其他泛型
+
+  public class XXXAsyncHandler_DynSncpAsyncHandler extends XXXAsyncHandler implements OldSncpHandler {
+
+      private OldSncpHandler sncphandler;
+
+      private CompletableFuture sncpfuture;
+
+      @ConstructorParameters({"sncphandler"})
+      public XXXAsyncHandler_DynSncpAsyncHandler(OldSncpHandler sncphandler) {
+          super();
+          this.sncphandler = sncphandler;
+      }
+
+      @Override
+         *      public void completed(Object result, Object attachment) {
+         *          sncphandler.completed(result, attachment);
+         *      }
+         *
+         *      @Override
+         *      public void failed(Throwable exc, Object attachment) {
+         *          sncphandler.failed(exc, attachment);
+         *      }
+         *
+         *      @Override
+         *      public Object[] sncp_getParams() {
+         *          return sncphandler.sncp_getParams();
+         *      }
+         *
+         *      @Override
+         *      public void sncp_setParams(Object... params) {
+         *          sncphandler.sncp_setParams(params);
+         *      }
+         *
+         *      @Override
+         *      public void sncp_setFuture(CompletableFuture future) {
+         *          this.sncpfuture = future;
+         *      }
+         *
+         *      @Override
+         *      public CompletableFuture sncp_getFuture() {
+         *          return this.sncpfuture;
+         *      }
+         *  }
+         *
+         * 
+ * + * @param handlerClass CompletionHandler类型或子类 + * + * @return Creator + */ + public static Creator createCreator(Class handlerClass) { + //------------------------------------------------------------- + final boolean handlerinterface = handlerClass.isInterface(); + final String handlerClassName = handlerClass.getName().replace('.', '/'); + final String sncpHandlerName = OldSncpHandler.class.getName().replace('.', '/'); + final String cpDesc = Type.getDescriptor(ConstructorParameters.class); + final String sncpHandlerDesc = Type.getDescriptor(OldSncpHandler.class); + final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class); + final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + OldSncpHandler.class.getSimpleName() + + "__" + handlerClass.getName().replace('.', '/').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; + return Creator.create(newHandlerClazz); + } catch (Throwable ex) { + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName}); + + { //handler 属性 + fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null); + fv.visitEnd(); + } + { //future 属性 + fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null); + fv.visitEnd(); + } + {//构造方法 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + sncpHandlerDesc + ")V", null, null)); + //mv.setDebug(true); + { + av0 = mv.visitAnnotation(cpDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "sncphandler"); + av1.visitEnd(); + } + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + for (java.lang.reflect.Method method : handlerClass.getMethods()) { // + if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); + Class returnType = method.getReturnType(); + if (returnType == void.class) { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + } else if (returnType.isPrimitive()) { + mv.visitInsn(ICONST_0); + if (returnType == long.class) { + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == float.class) { + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == double.class) { + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 1); + } else { + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + } + } else { + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + } + mv.visitEnd(); + } + } + { // sncp_getParams + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // sncp_setParams + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { // sncp_setFuture + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { // sncp_getFuture + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = (Class) new ClassLoader(handlerClass.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); + return Creator.create(newClazz); + } + + } + + public static class DefaultSncpAsyncHandler implements OldSncpHandler { + + //为了在回调函数中调用_callParameter方法 + protected Object[] params; + + protected SncpServletAction action; + + protected BsonReader in; + + protected BsonWriter out; + + protected SncpRequest request; + + protected SncpResponse response; + + protected CompletableFuture future; + + protected Logger logger; + + public DefaultSncpAsyncHandler(Logger logger, SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) { + this.logger = logger; + this.action = action; + this.in = in; + this.out = out; + this.request = request; + this.response = response; + } + + @Override + public void completed(Object result, Object attachment) { + try { + action._callParameter(out, sncp_getParams()); + action.convert.convertTo(out, Object.class, result); + response.finish(0, out); + } catch (Exception e) { + failed(e, attachment); + } finally { + action.convert.offerBsonReader(in); + action.convert.offerBsonWriter(out); + } + } + + @Override + public void failed(Throwable exc, Object attachment) { + response.getContext().getLogger().log(Level.INFO, "Sncp execute error(" + request + ")", exc); + response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); + } + + @Override + public Object[] sncp_getParams() { + return params; + } + + @Override + public void sncp_setParams(Object... params) { + this.params = params; + } + + @Override + public void sncp_setFuture(CompletableFuture future) { + this.future = future; + } + + @Override + public CompletableFuture sncp_getFuture() { + return this.future; + } + + } +} diff --git a/src/main/java/org/redkale/net/sncp/Sncp.java b/src/main/java/org/redkale/net/sncp/Sncp.java index 028b627e3..353dd1c29 100644 --- a/src/main/java/org/redkale/net/sncp/Sncp.java +++ b/src/main/java/org/redkale/net/sncp/Sncp.java @@ -249,14 +249,14 @@ public abstract class Sncp { } } - public static SncpOldClient getSncpOldClient(Service service) { + public static OldSncpClient getSncpOldClient(Service service) { if (service == null || !isSncpDyn(service)) { return null; } try { Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_client"); ts.setAccessible(true); - return (SncpOldClient) ts.get(service); + return (OldSncpClient) ts.get(service); } catch (Exception e) { throw new SncpException(service + " not found " + FIELDPREFIX + "_client"); } @@ -299,7 +299,7 @@ public abstract class Sncp { if (!isSncpDyn(service)) { return false; } - SncpOldClient client = getSncpOldClient(service); + OldSncpClient client = getSncpOldClient(service); client.setRemoteGroups(groups); if (client.getRemoteGroupTransport() != null) { client.getRemoteGroupTransport().updateRemoteAddresses(addresses); @@ -340,18 +340,10 @@ public abstract class Sncp { throw new SncpException(param + " must have a empty parameter Constructor"); } for (Method m : param.getMethods()) { - if (m.getName().equals("completed") && Modifier.isFinal(m.getModifiers())) { + if (m.getName().equals("completed") && m.getParameterCount() == 2 && Modifier.isFinal(m.getModifiers())) { throw new SncpException(param + "'s completed method cannot final modifier"); - } else if (m.getName().equals("failed") && Modifier.isFinal(m.getModifiers())) { + } else if (m.getName().equals("failed") && m.getParameterCount() == 2 && Modifier.isFinal(m.getModifiers())) { throw new SncpException(param + "'s failed method cannot final modifier"); - } else if (m.getName().equals("sncp_getParams") && Modifier.isFinal(m.getModifiers())) { - throw new SncpException(param + "'s sncp_getParams method cannot final modifier"); - } else if (m.getName().equals("sncp_setParams") && Modifier.isFinal(m.getModifiers())) { - throw new SncpException(param + "'s sncp_setParams method cannot final modifier"); - } else if (m.getName().equals("sncp_setFuture") && Modifier.isFinal(m.getModifiers())) { - throw new SncpException(param + "'s sncp_setFuture method cannot final modifier"); - } else if (m.getName().equals("sncp_getFuture") && Modifier.isFinal(m.getModifiers())) { - throw new SncpException(param + "'s sncp_getFuture method cannot final modifier"); } } } @@ -375,6 +367,54 @@ public abstract class Sncp { return sb.toString(); } + //获取一个clazz内所有未被实现的方法 + public static List loadNotImplMethods(Class clazz) { + LinkedHashSet types = new LinkedHashSet<>(); + loadAllSubClasses(clazz, types); + List methods = new ArrayList<>(); + Set ms = new HashSet<>(); + for (Class c : types) { + for (Method m : c.getDeclaredMethods()) { + if (c.isInterface() || Modifier.isAbstract(m.getModifiers())) { + StringBuilder sb = new StringBuilder(); //不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致 + sb.append(m.getName()); + sb.append('('); + boolean first = true; + for (Class pt : m.getParameterTypes()) { + if (!first) { + sb.append(','); + } + sb.append(pt.getName()); + first = false; + } + sb.append(')'); + String key = sb.toString(); + Uint128 a = actionid(m); + if (!ms.contains(key)) { + methods.add(m); + ms.add(key); + } + } + } + } + return methods; + } + + private static void loadAllSubClasses(Class clazz, LinkedHashSet types) { + if (clazz == null || clazz == Object.class) { + return; + } + types.add(clazz); + if (clazz.getSuperclass() != null) { + loadAllSubClasses(clazz.getSuperclass(), types); + } + if (clazz.getInterfaces() != null) { + for (Class sub : clazz.getInterfaces()) { + loadAllSubClasses(sub, types); + } + } + } + /** *
      * public class TestService implements Service{
@@ -403,7 +443,7 @@ public abstract class Sncp {
      *
      * private AnyValue _redkale_conf;
      *
-     * private SncpOldClient _redkale_client;
+     * private OldSncpClient _redkale_client;
      *
      * @Override
      *      public String toString() {
@@ -436,9 +476,9 @@ public abstract class Sncp {
             throw new SncpException(serviceImplClass + " is abstract");
         }
         final String supDynName = serviceImplClass.getName().replace('.', '/');
-        final String clientName = SncpOldClient.class.getName().replace('.', '/');
+        final String clientName = OldSncpClient.class.getName().replace('.', '/');
         final String resDesc = Type.getDescriptor(Resource.class);
-        final String clientDesc = Type.getDescriptor(SncpOldClient.class);
+        final String clientDesc = Type.getDescriptor(OldSncpClient.class);
         final String anyValueDesc = Type.getDescriptor(AnyValue.class);
         final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
         ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
@@ -481,7 +521,7 @@ public abstract class Sncp {
             av0.visit("type", Type.getType(Type.getDescriptor(getResourceType(serviceImplClass))));
             av0.visitEnd();
         }
-        { //给新类加上 原有的Annotation
+        { //给新类加上原有的Annotation
             for (Annotation ann : serviceImplClass.getAnnotations()) {
                 if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) {
                     continue;
@@ -623,12 +663,12 @@ public abstract class Sncp {
                     }
                 } while ((loop = loop.getSuperclass()) != Object.class);
             }
-            SncpOldClient client = null;
+            OldSncpClient client = null;
             {
                 try {
                     Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
                     c.setAccessible(true);
-                    client = new SncpOldClient(name, serviceImplClass, service, messageAgent, transportFactory, false, newClazz, clientSncpAddress);
+                    client = new OldSncpClient(name, serviceImplClass, service, messageAgent, transportFactory, false, newClazz, clientSncpAddress);
                     c.set(service, client);
                     if (transportFactory != null) {
                         transportFactory.addSncpService(service);
@@ -677,7 +717,7 @@ public abstract class Sncp {
      *
      * private AnyValue _redkale_conf;
      *
-     * private SncpOldClient _redkale_client;
+     * private OldSncpClient _redkale_client;
      *
      * @Override
      *      public void createSomeThing(TestBean bean){
@@ -735,9 +775,9 @@ public abstract class Sncp {
             return null;
         }
         final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/');
-        final String clientName = SncpOldClient.class.getName().replace('.', '/');
+        final String clientName = OldSncpClient.class.getName().replace('.', '/');
         final String resDesc = Type.getDescriptor(Resource.class);
-        final String clientDesc = Type.getDescriptor(SncpOldClient.class);
+        final String clientDesc = Type.getDescriptor(OldSncpClient.class);
         final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
         final String anyValueDesc = Type.getDescriptor(AnyValue.class);
         final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
@@ -747,7 +787,7 @@ public abstract class Sncp {
             Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
             Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz;
             T service = (T) newClazz.getDeclaredConstructor().newInstance();
-            SncpOldClient client = new SncpOldClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
+            OldSncpClient client = new OldSncpClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
             client.setRemoteGroups(groups);
             if (transportFactory != null) {
                 client.setRemoteGroupTransport(transportFactory.loadTransport(clientAddress, groups));
@@ -803,7 +843,7 @@ public abstract class Sncp {
             av0.visit("type", Type.getType(Type.getDescriptor(serviceTypeOrImplClass)));
             av0.visitEnd();
         }
-        { //给新类加上 原有的Annotation
+        { //给新类加上原有的Annotation
             for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) {
                 if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) {
                     continue;
@@ -972,7 +1012,7 @@ public abstract class Sncp {
         RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
         try {
             T service = (T) newClazz.getDeclaredConstructor().newInstance();
-            SncpOldClient client = new SncpOldClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
+            OldSncpClient client = new OldSncpClient(name, serviceTypeOrImplClass, service, messageAgent, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
             client.setRemoteGroups(groups);
             if (transportFactory != null) {
                 client.setRemoteGroupTransport(transportFactory.loadTransport(clientAddress, groups));
diff --git a/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java b/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java
index d09e7a050..8d45bdb58 100644
--- a/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java
+++ b/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java
@@ -1,322 +1,203 @@
-/*
- * 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.net.sncp;
-
-import java.nio.channels.CompletionHandler;
-import java.util.concurrent.CompletableFuture;
-import java.util.logging.*;
-import org.redkale.annotation.ConstructorParameters;
-import org.redkale.asm.*;
-import static org.redkale.asm.Opcodes.*;
-import org.redkale.convert.bson.*;
-import org.redkale.net.sncp.SncpDynServlet.SncpServletAction;
-import org.redkale.util.*;
-
-/**
- * 异步回调函数  
- * - * public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler - * - * - *

- * 详情见: https://redkale.org - * - * @author zhangjx - * @param 结果对象的泛型 - * @param 附件对象的泛型 - */ -public interface SncpAsyncHandler extends CompletionHandler { - - public Object[] sncp_getParams(); - - public void sncp_setParams(Object... params); - - public void sncp_setFuture(CompletableFuture future); - - public CompletableFuture sncp_getFuture(); - - static class Factory { - - /** - *

-         *
-         * 考虑点:
-         *      1、CompletionHandler子类是接口,且还有其他多个方法
-         *      2、CompletionHandler子类是类, 需要继承,且必须有空参数构造函数
-         *      3、CompletionHandler子类无论是接口还是类,都可能存在其他泛型
-         *
-         *  public class XXXAsyncHandler_DynSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler {
-         *
-         *      private SncpAsyncHandler sncphandler;
-         *
-         *      private CompletableFuture sncpfuture;
-         *
-         *      @ConstructorParameters({"sncphandler"})
-         *      public XXXAsyncHandler_DynSncpAsyncHandler(SncpAsyncHandler sncphandler) {
-         *          super();
-         *          this.sncphandler = sncphandler;
-         *      }
-         *
-         *      @Override
-         *      public void completed(Object result, Object attachment) {
-         *          sncphandler.completed(result, attachment);
-         *      }
-         *
-         *      @Override
-         *      public void failed(Throwable exc, Object attachment) {
-         *          sncphandler.failed(exc, attachment);
-         *      }
-         *
-         *      @Override
-         *      public Object[] sncp_getParams() {
-         *          return sncphandler.sncp_getParams();
-         *      }
-         *
-         *      @Override
-         *      public void sncp_setParams(Object... params) {
-         *          sncphandler.sncp_setParams(params);
-         *      }
-         *
-         *      @Override
-         *      public void sncp_setFuture(CompletableFuture future) {
-         *          this.sncpfuture = future;
-         *      }
-         *
-         *      @Override
-         *      public CompletableFuture sncp_getFuture() {
-         *          return this.sncpfuture;
-         *      }
-         *  }
-         *
-         * 
- * - * @param handlerClass CompletionHandler类型或子类 - * - * @return Creator - */ - public static Creator createCreator(Class handlerClass) { - //------------------------------------------------------------- - final boolean handlerinterface = handlerClass.isInterface(); - final String handlerClassName = handlerClass.getName().replace('.', '/'); - final String sncpHandlerName = SncpAsyncHandler.class.getName().replace('.', '/'); - final String cpDesc = Type.getDescriptor(ConstructorParameters.class); - final String sncpHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class); - final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class); - final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + SncpAsyncHandler.class.getSimpleName() - + "__" + handlerClass.getName().replace('.', '/').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; - return Creator.create(newHandlerClazz); - } catch (Throwable ex) { - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName}); - - { //handler 属性 - fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null); - fv.visitEnd(); - } - { //future 属性 - fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null); - fv.visitEnd(); - } - {//构造方法 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + sncpHandlerDesc + ")V", null, null)); - //mv.setDebug(true); - { - av0 = mv.visitAnnotation(cpDesc, true); - { - AnnotationVisitor av1 = av0.visitArray("value"); - av1.visit(null, "sncphandler"); - av1.visitEnd(); - } - av0.visitEnd(); - } - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - - for (java.lang.reflect.Method method : handlerClass.getMethods()) { // - if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); - Class returnType = method.getReturnType(); - if (returnType == void.class) { - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - } else if (returnType.isPrimitive()) { - mv.visitInsn(ICONST_0); - if (returnType == long.class) { - mv.visitInsn(LRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == float.class) { - mv.visitInsn(FRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == double.class) { - mv.visitInsn(DRETURN); - mv.visitMaxs(2, 1); - } else { - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - } - } else { - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - } - mv.visitEnd(); - } - } - { // sncp_getParams - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // sncp_setParams - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - { // sncp_setFuture - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - { // sncp_getFuture - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - Class newClazz = (Class) new ClassLoader(handlerClass.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); - return Creator.create(newClazz); - } - - } - - public static class DefaultSncpAsyncHandler implements SncpAsyncHandler { - - //为了在回调函数中调用_callParameter方法 - protected Object[] params; - - protected SncpServletAction action; - - protected BsonReader in; - - protected BsonWriter out; - - protected SncpRequest request; - - protected SncpResponse response; - - protected CompletableFuture future; - - protected Logger logger; - - public DefaultSncpAsyncHandler(Logger logger, SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) { - this.logger = logger; - this.action = action; - this.in = in; - this.out = out; - this.request = request; - this.response = response; - } - - @Override - public void completed(Object result, Object attachment) { - try { - action._callParameter(out, sncp_getParams()); - action.convert.convertTo(out, Object.class, result); - response.finish(0, out); - } catch (Exception e) { - failed(e, attachment); - } finally { - action.convert.offerBsonReader(in); - action.convert.offerBsonWriter(out); - } - } - - @Override - public void failed(Throwable exc, Object attachment) { - response.getContext().getLogger().log(Level.INFO, "Sncp execute error(" + request + ")", exc); - response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); - } - - @Override - public Object[] sncp_getParams() { - return params; - } - - @Override - public void sncp_setParams(Object... params) { - this.params = params; - this.request.sncp_setParams(this.action, this.logger, params); - } - - @Override - public void sncp_setFuture(CompletableFuture future) { - this.future = future; - } - - @Override - public CompletableFuture sncp_getFuture() { - return this.future; - } - - } -} +/* + * + */ +package org.redkale.net.sncp; + +import java.lang.reflect.*; +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import org.redkale.asm.*; +import static org.redkale.asm.Opcodes.ACC_FINAL; +import static org.redkale.asm.Opcodes.ACC_PRIVATE; +import static org.redkale.asm.Opcodes.ACC_PUBLIC; +import static org.redkale.asm.Opcodes.ACC_SUPER; +import static org.redkale.asm.Opcodes.ACONST_NULL; +import static org.redkale.asm.Opcodes.ALOAD; +import static org.redkale.asm.Opcodes.ARETURN; +import static org.redkale.asm.Opcodes.DRETURN; +import static org.redkale.asm.Opcodes.FRETURN; +import static org.redkale.asm.Opcodes.GETFIELD; +import static org.redkale.asm.Opcodes.ICONST_0; +import static org.redkale.asm.Opcodes.INVOKEINTERFACE; +import static org.redkale.asm.Opcodes.INVOKESPECIAL; +import static org.redkale.asm.Opcodes.IRETURN; +import static org.redkale.asm.Opcodes.LRETURN; +import static org.redkale.asm.Opcodes.PUTFIELD; +import static org.redkale.asm.Opcodes.RETURN; +import static org.redkale.asm.Opcodes.V11; +import org.redkale.asm.Type; +import org.redkale.util.*; + +/** + * 异步回调函数 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @param 结果对象的泛型 + * @param 附件对象的泛型 + * + * @since 2.8.0 + */ +public interface SncpAsyncHandler extends CompletionHandler { + + public static SncpAsyncHandler createHandler(Class handlerClazz, CompletionHandler realHandler) { + Objects.requireNonNull(handlerClazz); + Objects.requireNonNull(realHandler); + if (handlerClazz == CompletionHandler.class) { + return new SncpAsyncHandler() { + @Override + public void completed(Object result, Object attachment) { + realHandler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) { + realHandler.failed(exc, attachment); + } + }; + } + return HandlerInner.creatorMap.computeIfAbsent(handlerClazz, handlerClass -> { + //------------------------------------------------------------- + final boolean handlerInterface = handlerClass.isInterface(); + final Class sncpHandlerClass = SncpAsyncHandler.class; + final String handlerClassName = handlerClass.getName().replace('.', '/'); + final String sncpHandlerName = sncpHandlerClass.getName().replace('.', '/'); + final String cpDesc = Type.getDescriptor(org.redkale.annotation.ConstructorParameters.class); + final String realHandlerName = CompletionHandler.class.getName().replace('.', '/'); + final String realHandlerDesc = Type.getDescriptor(CompletionHandler.class); + final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + sncpHandlerClass.getSimpleName() + + "__" + handlerClass.getName().replace('.', '/').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; + return (Creator) Creator.create(newHandlerClazz); + } catch (Throwable ex) { + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerInterface ? "java/lang/Object" : handlerClassName, handlerInterface && handlerClass != sncpHandlerClass ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName}); + + { //handler 属性 + fv = cw.visitField(ACC_PRIVATE, "realHandler", realHandlerDesc, null, null); + fv.visitEnd(); + } + {//构造方法 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + realHandlerDesc + ")V", null, null)); + //mv.setDebug(true); + { + av0 = mv.visitAnnotation(cpDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "realHandler"); + av1.visitEnd(); + } + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, handlerInterface ? "java/lang/Object" : handlerClassName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "realHandler", realHandlerDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + for (Method method : Sncp.loadNotImplMethods(handlerClass)) { // + int mod = method.getModifiers(); + String methodDesc = Type.getMethodDescriptor(method); + if (Modifier.isPublic(mod) && "completed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", methodDesc, null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "realHandler", realHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, realHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); +// if (!"(Ljava/lang/Object;Ljava/lang/Object;)V".equals(methodDesc)) { +// mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null)); +// mv.visitVarInsn(ALOAD, 0); +// mv.visitVarInsn(ALOAD, 1); +// mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); +// mv.visitVarInsn(ALOAD, 2); +// mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); +// mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "completed", methodDesc, false); +// mv.visitInsn(RETURN); +// mv.visitMaxs(3, 3); +// mv.visitEnd(); +// } + } else if (Modifier.isPublic(mod) && "failed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", methodDesc, null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "realHandler", realHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, realHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); +// if (!"(Ljava/lang/Throwable;Ljava/lang/Object;)V".equals(methodDesc)) { +// mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", null, null)); +// mv.visitVarInsn(ALOAD, 0); +// mv.visitVarInsn(ALOAD, 1); +// mv.visitVarInsn(ALOAD, 2); +// mv.visitTypeInsn(CHECKCAST, "java/lang/Object"); +// mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "failed", methodDesc, false); +// mv.visitInsn(RETURN); +// mv.visitMaxs(3, 3); +// mv.visitEnd(); +// } + } else if (handlerInterface || Modifier.isAbstract(mod)) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); + Class returnType = method.getReturnType(); + if (returnType == void.class) { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + } else if (returnType.isPrimitive()) { + mv.visitInsn(ICONST_0); + if (returnType == long.class) { + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == float.class) { + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == double.class) { + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 1); + } else { + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + } + } else { + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + } + mv.visitEnd(); + } + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = new ClassLoader((handlerClass != CompletionHandler.class ? handlerClass : sncpHandlerClass).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); + return (Creator) Creator.create(newClazz); + }).create(realHandler); + } + + static class HandlerInner { + + static final Map> creatorMap = new ConcurrentHashMap<>(); + } + +} diff --git a/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java b/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java index 60b1e3e4a..7c71b7572 100644 --- a/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java +++ b/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java @@ -20,7 +20,7 @@ import org.redkale.util.*; */ public class SncpDispatcherServlet extends DispatcherServlet { - private final ReentrantLock sncplock = new ReentrantLock(); + private final ReentrantLock updateLock = new ReentrantLock(); private final byte[] pongBytes = Sncp.getPongBytes(); @@ -30,7 +30,7 @@ public class SncpDispatcherServlet extends DispatcherServlet SncpServlet removeSncpServlet(Service service) { SncpServlet rs = null; - sncplock.lock(); + updateLock.lock(); try { for (SncpServlet servlet : getServlets()) { if (servlet.service == service) { @@ -60,7 +60,7 @@ public class SncpDispatcherServlet extends DispatcherServlet actions = new HashMap<>(); + private final HashMap actions = new HashMap<>(); - public SncpDynServlet(final BsonConvert convert, final String serviceResourceName, final Class serviceResourceType, final Service service, + public SncpDynServlet(final String resourceName, final Class resourceType, final Service service, final AtomicInteger maxTypeLength, AtomicInteger maxNameLength) { - super(serviceResourceName, serviceResourceType, service); + super(resourceName, resourceType, service); this.maxTypeLength = maxTypeLength; this.maxNameLength = maxNameLength; - this.serviceid = Sncp.serviceid(serviceResourceName, serviceResourceType); + this.serviceid = Sncp.serviceid(resourceName, resourceType); RedkaleClassLoader.putReflectionPublicMethods(service.getClass().getName()); - for (Map.Entry en : Sncp.loadMethodActions(serviceResourceType).entrySet()) { - SncpServletAction action; + for (Map.Entry en : Sncp.loadMethodActions(resourceType).entrySet()) { + SncpActionServlet action; try { - action = SncpServletAction.create(service, serviceid, en.getKey(), en.getValue()); + action = SncpActionServlet.create(resourceName, resourceType, service, serviceid, en.getKey(), en.getValue()); } catch (RuntimeException e) { - throw new SncpException(en.getValue() + " create " + SncpServletAction.class.getSimpleName() + " error", e); + throw new SncpException(en.getValue() + " create " + SncpActionServlet.class.getSimpleName() + " error", e); } - action.convert = convert; actions.put(en.getKey(), action); } - maxNameLength.set(Math.max(maxNameLength.get(), serviceResourceName.length() + 1)); - maxTypeLength.set(Math.max(maxTypeLength.get(), serviceType.getName().length())); + maxNameLength.set(Math.max(maxNameLength.get(), resourceName.length() + 1)); + maxTypeLength.set(Math.max(maxTypeLength.get(), resourceType.getName().length())); } @Override @@ -85,11 +80,11 @@ public final class SncpDynServlet extends SncpServlet { } @Override - public int compareTo(SncpServlet o0) { - if (!(o0 instanceof SncpDynServlet)) { + public int compareTo(SncpServlet other) { + if (!(other instanceof OldSncpDynServlet)) { return 1; } - SncpDynServlet o = (SncpDynServlet) o0; + OldSncpDynServlet o = (OldSncpDynServlet) other; int rs = this.serviceType.getName().compareTo(o.serviceType.getName()); if (rs == 0) { rs = this.serviceName.compareTo(o.serviceName); @@ -100,56 +95,28 @@ public final class SncpDynServlet extends SncpServlet { @Override @SuppressWarnings("unchecked") public void execute(SncpRequest request, SncpResponse response) throws IOException { - final SncpServletAction action = actions.get(request.getHeader().getActionid()); + final SncpActionServlet action = actions.get(request.getHeader().getActionid()); //logger.log(Level.FINEST, "sncpdyn.execute: " + request + ", " + (action == null ? "null" : action.method)); if (action == null) { response.finish(SncpResponse.RETCODE_ILLACTIONID, null); //无效actionid } else { - BsonWriter out = action.convert.pollBsonWriter(); - out.writePlaceholderTo(HEADER_SIZE); - BsonReader in = action.convert.pollBsonReader(); - SncpAsyncHandler handler = null; try { - if (action.handlerFuncParamIndex >= 0) { - if (action.handlerFuncParamType == CompletionHandler.class) { - handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response); + if (response.inNonBlocking()) { + if (action.nonBlocking) { + action.execute(request, response); } else { - Creator creator = action.handlerCreator; - if (creator == null) { - creator = SncpAsyncHandler.Factory.createCreator(action.handlerFuncParamType); - action.handlerCreator = creator; - } - handler = creator.create(new DefaultSncpAsyncHandler(logger, action, in, out, request, response)); - } - } else if (action.boolReturnTypeFuture) { - handler = new DefaultSncpAsyncHandler(logger, action, in, out, request, response); - } - in.setBytes(request.getBody()); - action.action(in, out, handler); - if (handler == null) { - response.finish(0, out); - action.convert.offerBsonReader(in); - action.convert.offerBsonWriter(out); - } else if (action.boolReturnTypeFuture) { - CompletableFuture future = handler.sncp_getFuture(); - if (future == null) { - action._callParameter(out, handler.sncp_getParams()); - action.convert.convertTo(out, Object.class, null); - } else { - Object[] sncpParams = handler.sncp_getParams(); - future.whenComplete((v, e) -> { - if (e != null) { - response.getContext().getLogger().log(Level.SEVERE, "sncp CompleteAsync error(" + request + ")", e); - response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); - return; + response.updateNonBlocking(false); + response.getWorkExecutor().execute(() -> { + try { + action.execute(request, response); + } catch (Throwable t) { + response.getContext().getLogger().log(Level.WARNING, "Servlet occur exception. request = " + request, t); + response.finishError(t); } - action._callParameter(out, sncpParams); - action.convert.convertTo(out, Object.class, v); - response.finish(0, out); - action.convert.offerBsonReader(in); - action.convert.offerBsonWriter(out); }); } + } else { + action.execute(request, response); } } catch (Throwable t) { response.getContext().getLogger().log(Level.SEVERE, "sncp execute error(" + request + ")", t); @@ -158,42 +125,114 @@ public final class SncpDynServlet extends SncpServlet { } } - public static abstract class SncpServletAction { + public static abstract class SncpActionServlet extends SncpServlet { - public Method method; + protected final Method method; - public Creator handlerCreator; + protected final Uint128 serviceid; - protected boolean nonBlocking; + protected final Uint128 actionid; - @Resource - protected BsonConvert convert; + protected final boolean nonBlocking; - protected org.redkale.util.Attribute[] paramAttrs; // 为null表示无RpcCall处理,index=0固定为null, 其他为参数标记的RpcCall回调方法 + protected final java.lang.reflect.Type[] paramTypes; //第一个元素存放返回类型return type, void的返回参数类型为null, 数组长度为:1+参数个数 - protected java.lang.reflect.Type[] paramTypes; //index=0表示返回参数的type, void的返回参数类型为null + protected final java.lang.reflect.Type returnObjectType; //返回结果的CompletableFuture的结果泛型类型 - protected int handlerFuncParamIndex = -1; //handlerFuncParamIndex>=0表示存在CompletionHandler参数 + protected final int paramHandlerIndex; //>=0表示存在CompletionHandler参数 - protected Class handlerFuncParamType; //CompletionHandler参数的类型 + protected final Class paramHandlerType; //CompletionHandler参数的类型 - protected boolean boolReturnTypeFuture = false; // 返回结果类型是否为 CompletableFuture + protected final java.lang.reflect.Type paramHandlerResultType; //CompletionHandler.completed第一个参数的类型 - public abstract void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable; + protected final java.lang.reflect.Type returnFutureResultType; //返回结果的CompletableFuture的结果泛型类型 - //只有同步方法才调用 (没有CompletionHandler、CompletableFuture) - public final void _callParameter(final BsonWriter out, final Object... params) { - if (paramAttrs != null) { - for (int i = 1; i < paramAttrs.length; i++) { - org.redkale.util.Attribute attr = paramAttrs[i]; - if (attr == null) { - continue; + protected SncpActionServlet(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) { + super(resourceName, resourceType, service); + this.serviceid = serviceid; + this.actionid = actionid; + this.method = method; + + int handlerFuncIndex = -1; + Class handlerFuncType = null; + java.lang.reflect.Type handlerResultType = null; + try { + final Class[] paramClasses = method.getParameterTypes(); + for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数 + if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) { + handlerFuncIndex = i; + handlerFuncType = paramClasses[i]; + java.lang.reflect.Type handlerType = TypeToken.getGenericType(method.getTypeParameters()[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 gGenericType in " + method); + } + break; } - out.writeByte((byte) i); - convert.convertTo(out, attr.genericType(), attr.get(params[i - 1])); } + } catch (Throwable ex) { } - out.writeByte((byte) 0); + 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.paramHandlerType = handlerFuncType; + this.paramHandlerResultType = handlerResultType; + this.returnObjectType = originalReturnType; + if (CompletionStage.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); + } + this.nonBlocking = non == null ? (CompletionStage.class.isAssignableFrom(method.getReturnType()) || this.paramHandlerIndex >= 0) : false; + } + + @Override + public final void execute(SncpRequest request, SncpResponse response) throws IOException { + if (paramHandlerIndex > 0) { + response.paramAsyncHandler(paramHandlerType, 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() { @@ -225,103 +264,104 @@ public final class SncpDynServlet extends SncpServlet { * public TestService service; * * @Override - * public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable { - * TestBean arg1 = convert.convertFrom(paramTypes[1], in); - * String arg2 = convert.convertFrom(paramTypes[2], in); - * int arg3 = convert.convertFrom(paramTypes[3], in); - * Object rs = service.change(arg1, arg2, arg3); - * _callParameter(out, arg1, arg2, arg3); - * convert.convertTo(out, paramTypes[0], rs); - * } + * public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable { + * TestBean arg1 = convert.convertFrom(paramTypes[1], in); + * String arg2 = convert.convertFrom(paramTypes[2], in); + * int arg3 = convert.convertFrom(paramTypes[3], in); + * Object rs = service.change(arg1, arg2, arg3); + * _callParameter(out, arg1, arg2, arg3); + * convert.convertTo(out, paramTypes[0], rs); + * } * } * * class DynActionTestService_insert extends SncpServletAction { * - * public TestService service; + * public TestService service; * - * @Override - * public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable { - * SncpAsyncHandler arg0 = handler; - * 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); - * handler.sncp_setParams(arg0, arg1, arg2, arg3); - * service.insert(arg0, arg1, arg2, arg3); - * } + * @Override + * public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable { + * OldSncpHandler arg0 = handler; + * 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); + * handler.sncp_setParams(arg0, arg1, arg2, arg3); + * service.insert(arg0, arg1, arg2, arg3); + * } * } * * class DynActionTestService_update extends SncpServletAction { * - * public TestService service; + * public TestService service; * - * @Override - * public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable { - * long a1 = convert.convertFrom(paramTypes[1], in); - * short a2 = convert.convertFrom(paramTypes[2], in); - * SncpAsyncHandler a3 = handler; - * 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); - * handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3); - * service.update(a1, a2, a3, arg1, arg2, arg3); - * } + * @Override + * public void action(BsonReader in, BsonWriter out, OldSncpHandler handler) throws Throwable { + * long a1 = convert.convertFrom(paramTypes[1], in); + * short a2 = convert.convertFrom(paramTypes[2], in); + * OldSncpHandler a3 = handler; + * 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); + * handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3); + * service.update(a1, a2, a3, arg1, arg2, arg3); + * } * } * * * class DynActionTestService_changeName extends SncpServletAction { * - * public TestService service; + * public TestService service; * - * @Override - * public void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable { - * TestBean arg1 = convert.convertFrom(paramTypes[1], in); - * String arg2 = convert.convertFrom(paramTypes[2], in); - * int arg3 = convert.convertFrom(paramTypes[3], in); - * handler.sncp_setParams(arg1, arg2, arg3); - * CompletableFuture future = service.changeName(arg1, arg2, arg3); - * handler.sncp_setFuture(future); - * } + * @Override + * public void action(final BsonReader in, final BsonWriter out, final OldSncpHandler handler) throws Throwable { + * TestBean arg1 = convert.convertFrom(paramTypes[1], in); + * String arg2 = convert.convertFrom(paramTypes[2], in); + * int arg3 = convert.convertFrom(paramTypes[3], in); + * handler.sncp_setParams(arg1, arg2, arg3); + * CompletableFuture future = service.changeName(arg1, arg2, arg3); + * handler.sncp_setFuture(future); + * } * } * *

* - * @param service Service - * @param serviceid 类ID - * @param actionid 操作ID - * @param method 方法 + * @param resourceName 资源名 + * @param resourceType 资源类 + * @param service Service + * @param serviceid 类ID + * @param actionid 操作ID + * @param method 方法 * * @return SncpServletAction */ @SuppressWarnings("unchecked") - public static SncpServletAction create(final Service service, final Uint128 serviceid, final Uint128 actionid, final Method method) { - final Class serviceClass = service.getClass(); - final String supDynName = SncpServletAction.class.getName().replace('.', '/'); - final String serviceName = serviceClass.getName().replace('.', '/'); - final String convertName = BsonConvert.class.getName().replace('.', '/'); - final String handlerName = SncpAsyncHandler.class.getName().replace('.', '/'); - final String asyncHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class); - final String convertReaderDesc = Type.getDescriptor(BsonReader.class); - final String convertWriterDesc = Type.getDescriptor(BsonWriter.class); - final String serviceDesc = Type.getDescriptor(serviceClass); - final boolean boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType()); - final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + serviceClass.getName().replace('.', '_').replace('$', '_') + "__" + method.getName() + "__" + actionid; + public static SncpActionServlet create( + final String resourceName, + final Class resourceType, + 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 resourceTypeName = resourceType.getName().replace('.', '/'); + final String convertName = BsonConvert.class.getName().replace('.', '/'); + final String uint128Desc = Type.getDescriptor(Uint128.class); + final String convertDesc = Type.getDescriptor(BsonConvert.class); + final String bsonReaderDesc = Type.getDescriptor(BsonReader.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 boolean boolReturnTypeFuture = CompletionStage.class.isAssignableFrom(method.getReturnType()); + final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid; - int handlerFuncIndex = -1; - Class handlerFuncType = null; Class newClazz = null; try { Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; - final Class[] paramClasses = method.getParameterTypes(); - for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数 - if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) { - handlerFuncIndex = i; - handlerFuncType = paramClasses[i]; - break; - } - } } catch (Throwable ex) { } @@ -335,34 +375,44 @@ public final class SncpDynServlet extends SncpServlet { cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null); { - { - fv = cw.visitField(ACC_PUBLIC, "service", serviceDesc, null, null); - fv.visitEnd(); - } - fv.visitEnd(); - } - { // constructor方法 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(Ljava/lang/String;Ljava/lang/Class;Lorg/redkale/service/Service;" + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", null, null)); mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "()V", false); + 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;Lorg/redkale/service/Service;" + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", false); mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); + mv.visitMaxs(7, 7); mv.visitEnd(); } - String convertFromDesc = "(Ljava/lang/reflect/Type;" + convertReaderDesc + ")Ljava/lang/Object;"; + String convertFromDesc = "(Ljava/lang/reflect/Type;" + bsonReaderDesc + ")Ljava/lang/Object;"; try { convertFromDesc = Type.getMethodDescriptor(BsonConvert.class.getMethod("convertFrom", java.lang.reflect.Type.class, BsonReader.class)); } catch (Exception ex) { throw new SncpException(ex); //不可能会发生 } { // action方法 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + asyncHandlerDesc + ")V", null, new String[]{"java/lang/Throwable"})); + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/lang/Throwable"})); //mv.setDebug(true); + { //BsonConvert + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getBsonConvert", "()" + convertDesc, false); + mv.visitVarInsn(ASTORE, 3); + } + { //BsonReader + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getBsonReader", "()" + bsonReaderDesc, false); + mv.visitVarInsn(ASTORE, 4); + } int iconst = ICONST_1; int intconst = 1; - int store = 4; //action的参数个数+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) { @@ -373,24 +423,22 @@ public final class SncpDynServlet extends SncpServlet { } Sncp.checkAsyncModifier(paramClasses[i], method); handlerFuncIndex = i; - handlerFuncType = paramClasses[i]; - mv.visitVarInsn(ALOAD, 3); + 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, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); + mv.visitVarInsn(ALOAD, 3); mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class))); - mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 4); mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); mv.visitInsn(POP); continue; } - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); + mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;"); @@ -404,7 +452,7 @@ public final class SncpDynServlet extends SncpServlet { mv.visitLdcInsn(intconst); } mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 4); mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); int load = ALOAD; @@ -445,63 +493,21 @@ public final class SncpDynServlet extends SncpServlet { intconst++; store++; } - if (boolReturnTypeFuture || handlerFuncIndex >= 0) { //调用SncpAsyncHandler.setParams(Object... params) - mv.visitVarInsn(ALOAD, 3); - if (paramClasses.length < 6) { - mv.visitInsn(ICONST_0 + paramClasses.length); - } else if (paramClasses.length <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, paramClasses.length); - } else if (paramClasses.length <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, paramClasses.length); - } else { - mv.visitLdcInsn(paramClasses.length); - } - - mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); - int insn = 3; //action的参数个数 - for (int j = 0; j < paramClasses.length; j++) { - final Class pt = paramClasses[j]; - mv.visitInsn(DUP); - insn++; - if (j < 6) { - mv.visitInsn(ICONST_0 + j); - } else if (j <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, j); - } else if (j <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, j); - } else { - mv.visitLdcInsn(j); - } - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - Class bigclaz = TypeToken.primitiveToWrapper(pt); - mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false); - } else { - mv.visitVarInsn(ALOAD, insn); - } - mv.visitInsn(AASTORE); - } - mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true); - } { //调用service mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "service", serviceDesc); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()Lorg/redkale/service/Service;", false); + mv.visitTypeInsn(CHECKCAST, resourceTypeName); + mv.visitVarInsn(ASTORE, store); + + mv.visitVarInsn(ALOAD, store); for (int[] j : codes) { mv.visitVarInsn(j[0], j[1]); } - mv.visitMethodInsn(INVOKEVIRTUAL, serviceName, method.getName(), Type.getMethodDescriptor(method), false); + mv.visitMethodInsn(resourceType.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, resourceTypeName, method.getName(), Type.getMethodDescriptor(method), resourceType.isInterface()); + store++; } - - final Class returnClass = method.getReturnType(); - if (returnClass != void.class) { + if (method.getReturnType() != void.class) { + final Class returnClass = method.getReturnType(); if (returnClass.isPrimitive()) { Class bigClass = TypeToken.primitiveToWrapper(returnClass); try { @@ -512,78 +518,29 @@ public final class SncpDynServlet extends SncpServlet { } } mv.visitVarInsn(ASTORE, store); //11 - if (boolReturnTypeFuture) { - mv.visitVarInsn(ALOAD, 3); + + if (boolReturnTypeFuture) { //返回类型为CompletionStage + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureResultType", "Ljava/lang/reflect/Type;"); mv.visitVarInsn(ALOAD, store); - mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setFuture", "(Ljava/util/concurrent/CompletableFuture;)V", true); + mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishFuture", "(Ljava/lang/reflect/Type;Ljava/util/concurrent/CompletionStage;)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); } - } - if (!boolReturnTypeFuture && handlerFuncIndex < 0) { //同步方法 - //------------------------- _callParameter 方法 -------------------------------- - mv.visitVarInsn(ALOAD, 0); + } else { //void返回类型 mv.visitVarInsn(ALOAD, 2); - if (paramClasses.length < 6) { //参数总数量 - mv.visitInsn(ICONST_0 + paramClasses.length); - } else if (paramClasses.length <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, paramClasses.length); - } else if (paramClasses.length <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, paramClasses.length); - } else { - mv.visitLdcInsn(paramClasses.length); - } - mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); - int insn = 3;//action的参数个数 - for (int j = 0; j < paramClasses.length; j++) { - final Class pt = paramClasses[j]; - mv.visitInsn(DUP); - insn++; - if (j < 6) { - mv.visitInsn(ICONST_0 + j); - } else if (j <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, j); - } else if (j <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, j); - } else { - mv.visitLdcInsn(j); - } - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - Class bigclaz = TypeToken.primitiveToWrapper(pt); - mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false); - } else { - mv.visitVarInsn(ALOAD, insn); - } - mv.visitInsn(AASTORE); - } - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false); + mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false); } - //-------------------------直接返回 或者 调用convertTo方法 -------------------------------- - int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1; - if (boolReturnTypeFuture || returnClass == void.class) { //返回 - mv.visitInsn(RETURN); - maxStack = 8; - } else { //同步方法调用 - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;"); - mv.visitInsn(ICONST_0); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, store); - mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertTo", "(" + convertWriterDesc + "Ljava/lang/reflect/Type;Ljava/lang/Object;)V", false); - mv.visitInsn(RETURN); - store++; - } - mv.visitMaxs(maxStack, store); + mv.visitInsn(RETURN); + mv.visitMaxs(8, store); mv.visitEnd(); } cw.visitEnd(); @@ -621,23 +578,9 @@ public final class SncpDynServlet extends SncpServlet { } } } - NonBlocking non = method.getAnnotation(NonBlocking.class); - if (non == null) { - non = service.getClass().getAnnotation(NonBlocking.class); - } try { - SncpServletAction instance = (SncpServletAction) newClazz.getDeclaredConstructor().newInstance(); - instance.method = method; - instance.nonBlocking = non == null ? false : non.value(); - java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1]; - types[0] = originalReturnType; - System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length); - instance.paramTypes = types; - instance.handlerFuncParamIndex = handlerFuncIndex; - instance.handlerFuncParamType = handlerFuncType; - instance.boolReturnTypeFuture = boolReturnTypeFuture; - newClazz.getField("service").set(instance, service); - return instance; + 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/SncpRequest.java b/src/main/java/org/redkale/net/sncp/SncpRequest.java index 65ad00973..203f63554 100644 --- a/src/main/java/org/redkale/net/sncp/SncpRequest.java +++ b/src/main/java/org/redkale/net/sncp/SncpRequest.java @@ -8,7 +8,8 @@ package org.redkale.net.sncp; import java.io.Serializable; import java.nio.ByteBuffer; import java.util.Objects; -import java.util.logging.*; +import java.util.logging.Level; +import org.redkale.convert.bson.*; import org.redkale.net.Request; import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE; import org.redkale.util.Uint128; @@ -30,6 +31,8 @@ public class SncpRequest extends Request { protected static final int READ_STATE_END = 4; + protected final BsonReader reader = new BsonReader(); + protected int readState = READ_STATE_ROUTE; private SncpHeader header; @@ -61,6 +64,10 @@ public class SncpRequest extends Request { context.getLogger().log(Level.WARNING, "sncp buffer header.retcode not 0"); return -1; } + if (this.header.getBodyLength() > context.getMaxBody()) { + context.getLogger().log(Level.WARNING, "sncp buffer body.length must lower " + context.getMaxBody() + ", but " + this.header.getBodyLength()); + return -1; + } this.body = new byte[this.header.getBodyLength()]; this.readState = READ_STATE_BODY; } @@ -98,10 +105,6 @@ public class SncpRequest extends Request { this.keepAlive = true; } - //被SncpAsyncHandler.sncp_setParams调用 - protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) { - } - @Override public String toString() { return SncpRequest.class.getSimpleName() + "_" + Objects.hashCode(this) + "{header=" + this.header + ",bodyOffset=" + this.bodyOffset + ",body=[" + (this.body == null ? -1 : this.body.length) + "]}"; @@ -109,6 +112,7 @@ public class SncpRequest extends Request { @Override protected void recycle() { + this.reader.clear(); this.readState = READ_STATE_ROUTE; this.header = null; this.bodyOffset = 0; @@ -121,6 +125,14 @@ public class SncpRequest extends Request { return ping; } + public BsonConvert getBsonConvert() { + return context.getBsonConvert(); + } + + public BsonReader getBsonReader() { + return body == null ? null : reader.setBytes(body); + } + public byte[] getBody() { return body; } diff --git a/src/main/java/org/redkale/net/sncp/SncpResponse.java b/src/main/java/org/redkale/net/sncp/SncpResponse.java index 129f092c7..5df3af620 100644 --- a/src/main/java/org/redkale/net/sncp/SncpResponse.java +++ b/src/main/java/org/redkale/net/sncp/SncpResponse.java @@ -5,7 +5,9 @@ */ package org.redkale.net.sncp; -import java.util.concurrent.ExecutorService; +import java.lang.reflect.Type; +import java.nio.channels.CompletionHandler; +import java.util.concurrent.*; import org.redkale.convert.bson.BsonWriter; import org.redkale.net.Response; import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE; @@ -32,6 +34,24 @@ public class SncpResponse extends Response { private final int addrPort; + protected final BsonWriter writer = new BsonWriter(); + + protected final CompletionHandler realHandler = new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + finish(paramHandlerResultType, result); + } + + @Override + public void failed(Throwable exc, Object attachment) { + finishError(exc); + } + }; + + protected Type paramHandlerResultType; + + protected CompletionHandler paramAsyncHandler; + public static String getRetCodeInfo(int retcode) { if (retcode == RETCODE_ILLSERVICEID) { return "The serviceid is invalid"; @@ -57,6 +77,16 @@ public class SncpResponse extends Response { } } + public SncpResponse paramAsyncHandler(Class paramHandlerType, Type paramHandlerResultType) { + this.paramHandlerResultType = paramHandlerResultType; + this.paramAsyncHandler = paramHandlerType == CompletionHandler.class ? realHandler : SncpAsyncHandler.createHandler(paramHandlerType, realHandler); + return this; + } + + public T getParamAsyncHandler() { + return (T) this.paramAsyncHandler; + } + @Override protected void prepare() { super.prepare(); @@ -64,9 +94,16 @@ public class SncpResponse extends Response { @Override protected boolean recycle() { + writer.clear(); + this.paramHandlerResultType = null; + this.paramAsyncHandler = null; return super.recycle(); } + public BsonWriter getBsonWriter() { + return writer; + } + @Override protected ExecutorService getWorkExecutor() { return super.getWorkExecutor(); @@ -92,6 +129,36 @@ public class SncpResponse extends Response { finish(RETCODE_THROWEXCEPTION, null); } + public final void finishVoid() { + BsonWriter out = getBsonWriter(); + out.writePlaceholderTo(HEADER_SIZE); + finish(0, out); + } + + public final void finishFuture(final Type futureResultType, final CompletionStage future) { + if (future == null) { + finishVoid(); + } else { + future.whenComplete((v, t) -> { + if (t != null) { + finishError((Throwable) t); + } else { + finish(futureResultType, v); + } + }); + } + } + + public final void finish(final Type type, final Object result) { + BsonWriter out = getBsonWriter(); + out.writePlaceholderTo(HEADER_SIZE); + if (result != null || type != Void.class) { + out.writeByte((byte) 0); //body的第一个字节为0,表示返回结果对象,而不是参数回调对象 + context.getBsonConvert().convertTo(out, type, result); + } + finish(0, out); + } + //调用此方法时out已写入SncpHeader public void finish(final int retcode, final BsonWriter out) { if (out == null) { @@ -101,7 +168,8 @@ public class SncpResponse extends Response { return; } final ByteArray array = out.toByteArray(); - fillHeader(array, array.length() - HEADER_SIZE, retcode); + final int bodyLength = array.length() - HEADER_SIZE; + fillHeader(array, bodyLength, retcode); finish(array); } diff --git a/src/main/java/org/redkale/net/sncp/SncpServer.java b/src/main/java/org/redkale/net/sncp/SncpServer.java index 5f83e3dc5..616bf8999 100644 --- a/src/main/java/org/redkale/net/sncp/SncpServer.java +++ b/src/main/java/org/redkale/net/sncp/SncpServer.java @@ -8,7 +8,6 @@ package org.redkale.net.sncp; import java.util.List; import java.util.concurrent.atomic.*; import org.redkale.boot.Application; -import org.redkale.convert.bson.BsonFactory; import org.redkale.net.Server; import org.redkale.net.sncp.SncpContext.SncpContextConfig; import org.redkale.service.Service; @@ -28,7 +27,7 @@ public class SncpServer extends Server { protected final Method method; - protected final Type resultTypes; //void 必须设为 null + protected final Type returnObjectType; //void 必须设为 null protected final Type[] paramTypes; @@ -146,7 +146,7 @@ public final class SncpServiceInfo { SncpServiceAction(final Class serviceImplClass, Method method, Uint128 serviceid, Uint128 actionid) { this.actionid = actionid == null ? Sncp.actionid(method) : actionid; Type rt = TypeToken.getGenericType(method.getGenericReturnType(), serviceImplClass); - this.resultTypes = rt == void.class ? null : rt; + this.returnObjectType = rt == void.class ? null : rt; this.boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType()); this.futureCreator = boolReturnTypeFuture ? Creator.create((Class) method.getReturnType()) : null; this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass); diff --git a/src/main/java/org/redkale/net/sncp/SncpServlet.java b/src/main/java/org/redkale/net/sncp/SncpServlet.java index 3284a770d..3458f8e89 100644 --- a/src/main/java/org/redkale/net/sncp/SncpServlet.java +++ b/src/main/java/org/redkale/net/sncp/SncpServlet.java @@ -26,9 +26,9 @@ public abstract class SncpServlet extends Servlet { * * * - * @param type 泛型 + * @param paramType 泛型 * @param declaringClass 泛型依附类 * * @return Type */ - public static Type getGenericType(final Type type, final Type declaringClass) { - if (type == null || declaringClass == null) { - return type; + public static Type getGenericType(final Type paramType, final Type declaringClass) { + if (paramType == null || declaringClass == null) { + return paramType; } - if (type instanceof TypeVariable) { + if (paramType instanceof TypeVariable) { Type superType = null; Class declaringClass0 = null; if (declaringClass instanceof Class) { @@ -288,7 +288,7 @@ public abstract class TypeToken { if (superType instanceof ParameterizedType) { Map map = new HashMap<>(); parseType(map, declaringClass0); - Type rstype = getType(map, type); + Type rstype = getType(map, paramType); if (rstype instanceof Class) { return rstype; } @@ -314,7 +314,7 @@ public abstract class TypeToken { if (atas.length == asts.length) { for (int i = 0; i < asts.length; i++) { Type currt = asts[i]; - if (asts[i] != type && superPT.getRawType() instanceof Class) { + if (asts[i] != paramType && superPT.getRawType() instanceof Class) { if (asts[i] instanceof TypeVariable) { Class raw = (Class) superPT.getRawType(); @@ -345,24 +345,24 @@ public abstract class TypeToken { } while (raw != Object.class); } } - if (currt == type) { + if (currt == paramType) { if (atas[i] instanceof Class - && ((TypeVariable) type).getBounds().length == 1 - && ((TypeVariable) type).getBounds()[0] instanceof Class - && ((Class) ((TypeVariable) type).getBounds()[0]).isAssignableFrom((Class) atas[i])) { + && ((TypeVariable) paramType).getBounds().length == 1 + && ((TypeVariable) paramType).getBounds()[0] instanceof Class + && ((Class) ((TypeVariable) paramType).getBounds()[0]).isAssignableFrom((Class) atas[i])) { return atas[i]; } if (atas[i] instanceof Class - && ((TypeVariable) type).getBounds().length == 1 - && ((TypeVariable) type).getBounds()[0] instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) ((TypeVariable) type).getBounds()[0]; + && ((TypeVariable) paramType).getBounds().length == 1 + && ((TypeVariable) paramType).getBounds()[0] instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) ((TypeVariable) paramType).getBounds()[0]; if (pt.getRawType() instanceof Class && ((Class) pt.getRawType()).isAssignableFrom((Class) atas[i])) { return atas[i]; } } if (atas[i] instanceof ParameterizedType - && ((TypeVariable) type).getBounds().length == 1 - && ((TypeVariable) type).getBounds()[0] == Object.class) { + && ((TypeVariable) paramType).getBounds().length == 1 + && ((TypeVariable) paramType).getBounds()[0] == Object.class) { return atas[i]; } } @@ -372,7 +372,7 @@ public abstract class TypeToken { TypeVariable[] argTypes = ((Class) cycType.getRawType()).getTypeParameters(); if (argTypes.length == asts.length) { for (int i = 0; i < argTypes.length; i++) { - if (argTypes[i] == type) { + if (argTypes[i] == paramType) { if (atas[i] instanceof TypeVariable && ((TypeVariable) atas[i]).getBounds().length == 1 && ((TypeVariable) atas[i]).getBounds()[0] instanceof Class) { @@ -385,24 +385,24 @@ public abstract class TypeToken { } Type moreType = ((ParameterizedType) superType).getRawType(); if (moreType != Object.class) { - return getGenericType(type, moreType); + return getGenericType(paramType, moreType); } } - TypeVariable tv = (TypeVariable) type; + TypeVariable tv = (TypeVariable) paramType; if (tv.getBounds().length == 1) { return tv.getBounds()[0]; } - } else if (type instanceof GenericArrayType) { - final Type rst = getGenericType(((GenericArrayType) type).getGenericComponentType(), declaringClass); + } else if (paramType instanceof GenericArrayType) { + final Type rst = getGenericType(((GenericArrayType) paramType).getGenericComponentType(), declaringClass); return (GenericArrayType) () -> rst; } - if (type instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) type; + if (paramType instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) paramType; return createParameterizedType(getGenericType(pt.getOwnerType(), declaringClass), getGenericType(pt.getRawType(), declaringClass), getGenericType(pt.getActualTypeArguments(), declaringClass)); } - return type; + return paramType; } private static Type getType(Map map, Type type) { diff --git a/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java b/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java new file mode 100644 index 000000000..89470fb77 --- /dev/null +++ b/src/test/java/org/redkale/test/sncp/SncpHandlerTest.java @@ -0,0 +1,97 @@ +/* + * + */ +package org.redkale.test.sncp; + +import java.io.File; +import java.nio.channels.CompletionHandler; +import java.util.Map; +import org.junit.jupiter.api.Test; +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(); + } + + @Test + public void run() throws Exception { + SncpAsyncHandler.createHandler(CompletionHandler.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + if (main) { + System.out.println("handler result: " + result + ", attachment: " + attachment); + } + } + + @Override + public void failed(Throwable exc, Object attachment) { + + } + }).completed(1, 2); + + SncpAsyncHandler.createHandler(ITestHandler1.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + System.out.println("handler1 result: " + result + ", attachment: " + attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) { + + } + }).completed("name", "/user/"); + + SncpAsyncHandler.createHandler(ITestHandler2.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + System.out.println("handler2 result: " + result + ", attachment: " + attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) { + + } + }).completed("aaa", "bbb"); + + SncpAsyncHandler.createHandler(ITestHandler3.class, new CompletionHandler() { + @Override + public void completed(Object result, Object attachment) { + System.out.println("handler3 result: " + result + ", attachment: " + attachment); + } + + @Override + public void failed(Throwable exc, Object attachment) { + + } + }).completed("key1", "val1"); + } + + public static abstract class ITestHandler1 implements CompletionHandler { + + @Override + public abstract void completed(String result, File attachment); + } + + public static interface IClose { + + public void close(T val); + } + + public static interface ITestHandler2 extends CompletionHandler, IClose { + + } + + public static interface ITestHandler3 extends CompletionHandler, Map { + + } +} diff --git a/src/test/java/org/redkale/test/sncp/SncpTest.java b/src/test/java/org/redkale/test/sncp/SncpTest.java index 428064670..eef805f48 100644 --- a/src/test/java/org/redkale/test/sncp/SncpTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpTest.java @@ -163,6 +163,7 @@ public class SncpTest { conf.addValue("host", "0.0.0.0"); conf.addValue("port", "" + port); conf.addValue("protocol", protocol); + conf.addValue("maxbody", "" + (100 * 1024 * 1024)); SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory); Set set = new LinkedHashSet<>(); if (port2 > 0) { @@ -203,6 +204,7 @@ public class SncpTest { conf.addValue("host", "0.0.0.0"); conf.addValue("port", "" + (port2 < 10 ? 0 : port2)); conf.addValue("protocol", protocol); + conf.addValue("maxbody", "" + (100 * 1024 * 1024)); SncpServer server = new SncpServer(null, System.currentTimeMillis(), conf, factory); Set set = new LinkedHashSet<>(); set.add(new InetSocketAddress(myhost, port)); diff --git a/src/test/java/org/redkale/test/sncp/TestService.java b/src/test/java/org/redkale/test/sncp/TestService.java new file mode 100644 index 000000000..5a72da9e3 --- /dev/null +++ b/src/test/java/org/redkale/test/sncp/TestService.java @@ -0,0 +1,146 @@ +/* + * + */ +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.bson.*; +import org.redkale.net.sncp.SncpDynServlet.SncpActionServlet; +import org.redkale.net.sncp.*; +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) + public static 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 handler, TestBean bean, String name, int id) { + } + + @Override + public CompletableFuture changeName(TestBean bean, String name, int id) { + return null; + } + } + + public static class BooleanHandler implements CompletionHandler { + + @Override + public void completed(Boolean result, TestBean attachment) { + } + + @Override + public void failed(Throwable exc, TestBean attachment) { + } + + } + + public static 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 { + BsonConvert convert = request.getBsonConvert(); + BsonReader in = request.getBsonReader(); + 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 static 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 { + BsonConvert convert = request.getBsonConvert(); + BsonReader in = request.getBsonReader(); + 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 static 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 { + BsonConvert convert = request.getBsonConvert(); + BsonReader in = request.getBsonReader(); + 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 static 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 { + BsonConvert convert = request.getBsonConvert(); + BsonReader in = request.getBsonReader(); + 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 index 388ebea7c..879fc43b3 100644 --- a/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java +++ b/src/test/java/org/redkale/test/sncp/_DynLocalSncpTestService.java @@ -5,7 +5,6 @@ */ package org.redkale.test.sncp; -import org.redkale.net.sncp.*; import org.redkale.annotation.ResourceType; /** @@ -15,6 +14,5 @@ import org.redkale.annotation.ResourceType; @ResourceType(SncpTestIService.class) public class _DynLocalSncpTestService extends SncpTestServiceImpl { - private SncpOldClient _redkale_client; } diff --git a/src/test/java/org/redkale/test/util/TypeTokenTest.java b/src/test/java/org/redkale/test/util/TypeTokenTest.java new file mode 100644 index 000000000..b95b7484a --- /dev/null +++ b/src/test/java/org/redkale/test/util/TypeTokenTest.java @@ -0,0 +1,74 @@ +/* + * + */ +package org.redkale.test.util; + +import java.io.File; +import java.lang.reflect.*; +import java.nio.channels.CompletionHandler; +import org.junit.jupiter.api.*; +import org.redkale.util.TypeToken; + +/** + * + * @author zhangjx + */ +public class TypeTokenTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + TypeTokenTest test = new TypeTokenTest(); + test.main = true; + test.run(); + test.run2(); + } + + @Test + public void run() throws Exception { + Class serviceType = Service1.class; + Method method = serviceType.getMethod("test", String.class, CompletionHandler.class); + Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType); + Type resultType = null; + if (handlerType instanceof Class) { + resultType = Object.class; + } else if (handlerType instanceof ParameterizedType) { + resultType = TypeToken.getGenericType(((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); + } + if (!main) { + Assertions.assertEquals(resultType, String.class); + } + System.out.println("resultType = " + resultType); + } + + @Test + public void run2() throws Exception { + Class serviceType = Service2.class; + Method method = serviceType.getMethod("test", String.class, CompletionHandler.class); + Type handlerType = TypeToken.getGenericType(method.getGenericParameterTypes()[1], serviceType); + Type resultType = null; + if (handlerType instanceof Class) { + resultType = Object.class; + } else if (handlerType instanceof ParameterizedType) { + resultType = TypeToken.getGenericType(((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); + } + if (!main) { + Assertions.assertEquals(resultType, File.class); + } + System.out.println("resultType = " + resultType); + } + + public static abstract class Service1 { + + public abstract void test(String name, CompletionHandler handler); + } + + public static abstract class IService2 { + + public abstract void test(String name, CompletionHandler handler); + } + + public static abstract class Service2 extends IService2 { + + } +}