From 039ed0f5693d9dfeb3f4e8a9afa900150102f96f Mon Sep 17 00:00:00 2001 From: redkale Date: Wed, 22 Mar 2023 16:02:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96SncpClient=E7=9A=84=E6=96=B0?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/META-INF/application-template.xml | 15 +- .../java/org/redkale/boot/Application.java | 50 +- .../java/org/redkale/boot/ClassFilter.java | 217 ++++-- .../java/org/redkale/boot/NodeHttpServer.java | 34 +- .../java/org/redkale/boot/NodeServer.java | 135 ++-- .../java/org/redkale/boot/NodeSncpServer.java | 30 +- .../boot/watch/TransportWatchService.java | 159 ----- .../org/redkale/cluster/ClusterAgent.java | 12 +- .../java/org/redkale/convert/Convert.java | 1 + src/main/java/org/redkale/net/Server.java | 14 +- src/main/java/org/redkale/net/Transport.java | 1 + .../org/redkale/net/TransportFactory.java | 1 + .../org/redkale/net/TransportGroupInfo.java | 1 + .../org/redkale/net/TransportStrategy.java | 1 + .../java/org/redkale/net/client/Client.java | 153 +++-- .../org/redkale/net/client/ClientAddress.java | 5 +- .../redkale/net/client/ClientConnection.java | 20 +- .../net/http/HttpDispatcherServlet.java | 10 +- .../java/org/redkale/net/http/HttpServer.java | 157 +++-- src/main/java/org/redkale/net/http/Rest.java | 76 ++- .../org/redkale/net/http/WebSocketNode.java | 320 ++++++--- .../org/redkale/net/sncp/OldSncpClient.java | 19 +- src/main/java/org/redkale/net/sncp/Sncp.java | 391 +++-------- .../java/org/redkale/net/sncp/SncpClient.java | 69 +- .../redkale/net/sncp/SncpClientRequest.java | 15 +- .../net/sncp/SncpDispatcherServlet.java | 2 +- .../org/redkale/net/sncp/SncpDynServlet.java | 642 ------------------ ...cpServiceInfo.java => SncpRemoteInfo.java} | 78 ++- .../org/redkale/net/sncp/SncpRpcGroup.java | 152 +++++ .../org/redkale/net/sncp/SncpRpcGroups.java | 62 ++ .../java/org/redkale/net/sncp/SncpServer.java | 11 +- .../org/redkale/net/sncp/SncpServlet.java | 626 ++++++++++++++++- src/main/java/org/redkale/util/ByteArray.java | 26 +- src/main/java/org/redkale/util/Uint128.java | 5 +- .../redkale/test/service/ABMainService.java | 115 ++-- .../org/redkale/test/service/BCService.java | 29 +- .../org/redkale/test/service/CService.java | 24 +- .../test/sncp/SncpClientCodecTest.java | 8 +- .../java/org/redkale/test/sncp/SncpTest.java | 8 +- .../test/sncp/SncpTestServiceImpl.java | 7 +- .../org/redkale/test/sncp/TestService.java | 2 +- 41 files changed, 2030 insertions(+), 1673 deletions(-) delete mode 100644 src/main/java/org/redkale/boot/watch/TransportWatchService.java delete mode 100644 src/main/java/org/redkale/net/sncp/SncpDynServlet.java rename src/main/java/org/redkale/net/sncp/{SncpServiceInfo.java => SncpRemoteInfo.java} (82%) create mode 100644 src/main/java/org/redkale/net/sncp/SncpRpcGroup.java create mode 100644 src/main/java/org/redkale/net/sncp/SncpRpcGroups.java diff --git a/src/main/java/META-INF/application-template.xml b/src/main/java/META-INF/application-template.xml index 966b811f9..d2473330e 100644 --- a/src/main/java/META-INF/application-template.xml +++ b/src/main/java/META-INF/application-template.xml @@ -98,9 +98,8 @@ @@ -196,10 +195,10 @@ mq: 所属的MQ管理器,当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式 includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 - groups: 所属组的节点,多个节点值用;隔开,如果配置文件中存在多个SNCP协议的Server节点,需要显式指定group属性. + group: 所属组的节点, 不能指定多个group, 如果配置文件中存在多个SNCP协议的Server节点,需要显式指定group属性. 当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。 - 当 protocol != SNCP 时 group只能是空或者一个group的节点值,不能为多个节点值。 - 特殊值"$cluster", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息 + 当 protocol != SNCP 时 group只能是空或者一个group的节点值。 + 特殊值"$remote", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息 --> @@ -208,10 +207,10 @@ - + diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java index 598c982d4..b53381552 100644 --- a/src/main/java/org/redkale/boot/Application.java +++ b/src/main/java/org/redkale/boot/Application.java @@ -8,33 +8,33 @@ package org.redkale.boot; import java.io.*; import java.lang.reflect.*; import java.net.*; -import java.net.http.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.charset.*; -import java.nio.file.*; +import java.net.http.HttpClient; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; -import java.util.concurrent.locks.*; -import java.util.function.*; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; import java.util.logging.*; -import javax.net.ssl.*; -import org.redkale.annotation.*; +import javax.net.ssl.SSLContext; +import org.redkale.annotation.Resource; import org.redkale.boot.ClassFilter.FilterEntry; import org.redkale.cluster.*; -import org.redkale.convert.*; -import org.redkale.convert.bson.*; +import org.redkale.convert.Convert; +import org.redkale.convert.bson.BsonFactory; import org.redkale.convert.json.*; import org.redkale.mq.*; import org.redkale.net.*; import org.redkale.net.http.*; import org.redkale.net.sncp.*; -import org.redkale.service.*; +import org.redkale.service.Service; import org.redkale.source.*; import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.*; -import org.redkale.watch.*; +import org.redkale.watch.WatchServlet; /** * @@ -163,6 +163,9 @@ public final class Application { //SNCP传输端的TransportFactory, 注意: 只给SNCP使用 private final TransportFactory sncpTransportFactory; + //配置项里的group信息, 注意: 只给SNCP使用 + private final SncpRpcGroups sncpRpcGroups = new SncpRpcGroups(); + //给客户端使用,包含SNCP客户端、自定义数据库客户端连接池 private final AsyncIOGroup clientAsyncGroup; @@ -464,8 +467,8 @@ public final class Application { excludelib0 = excludelibConf.getValue("value"); } AnyValue transportConf = config.getAnyValue("transport"); - int groupsize = config.getAnyValues("group").length; - if (groupsize > 0 && transportConf == null) { + int groupSize = config.getAnyValues("group").length; + if (groupSize > 0 && transportConf == null) { transportConf = new DefaultAnyValue(); } if (transportConf != null) { @@ -473,7 +476,7 @@ public final class Application { bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), bufferCapacity), 32 * 1024); readTimeoutSeconds = transportConf.getIntValue("readTimeoutSeconds", readTimeoutSeconds); writeTimeoutSeconds = transportConf.getIntValue("writeTimeoutSeconds", writeTimeoutSeconds); - final int threads = parseLenth(transportConf.getValue("threads"), groupsize * Utility.cpus() * 2); + final int threads = parseLenth(transportConf.getValue("threads"), groupSize * Utility.cpus() * 2); bufferPoolSize = parseLenth(transportConf.getValue("bufferPoolSize"), threads * 4); } @@ -938,7 +941,7 @@ public final class Application { }); } if (!compileMode) { - properties.put(OldSncpClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName()); + properties.put(SncpClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName()); } } if (compileMode) { @@ -1155,7 +1158,6 @@ public final class Application { String sourceName = ((CacheClusterAgent) clusterAgent).getSourceName(); //必须在inject前调用,需要赋值Resourcable.name loadCacheSource(sourceName, false); } - clusterAgent.setTransportFactory(this.sncpTransportFactory); this.resourceFactory.inject(clusterAgent); clusterAgent.init(this.resourceFactory, clusterAgent.getConfig()); this.resourceFactory.register(ClusterAgent.class, clusterAgent); @@ -1329,14 +1331,19 @@ public final class Application { //------------------------------------------------------------------------ for (AnyValue conf : config.getAnyValues("group")) { final String group = conf.getValue("name", ""); + if (group.indexOf('$') >= 0) { + throw new RedkaleException(" name cannot contains '$' in " + group); + } final String protocol = conf.getValue("protocol", Transport.DEFAULT_NETPROTOCOL).toUpperCase(); if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) { throw new RedkaleException("Not supported Transport Protocol " + conf.getValue("protocol")); } + SncpRpcGroup rg = sncpRpcGroups.computeIfAbsent(group, protocol); TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, new LinkedHashSet<>()); for (AnyValue node : conf.getAnyValues("node")) { final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port")); ginfo.putAddress(addr); + rg.putAddress(addr); } sncpTransportFactory.addGroupInfo(ginfo); } @@ -2530,7 +2537,8 @@ public final class Application { return resourceFactory; } - public TransportFactory getSncpTransportFactory() { + @Deprecated + public TransportFactory getSncpTransportFactory2() { return sncpTransportFactory; } @@ -2574,6 +2582,10 @@ public final class Application { return new ArrayList<>(cacheSources); } + public SncpRpcGroups getSncpRpcGroups() { + return sncpRpcGroups; + } + public int getNodeid() { return nodeid; } diff --git a/src/main/java/org/redkale/boot/ClassFilter.java b/src/main/java/org/redkale/boot/ClassFilter.java index ccdeb3ca5..0ac445162 100644 --- a/src/main/java/org/redkale/boot/ClassFilter.java +++ b/src/main/java/org/redkale/boot/ClassFilter.java @@ -86,13 +86,17 @@ public final class ClassFilter { } public ClassFilter or(ClassFilter filter) { - if (ors == null) ors = new ArrayList<>(); + if (ors == null) { + ors = new ArrayList<>(); + } ors.add(filter); return this; } public ClassFilter and(ClassFilter filter) { - if (ands == null) ands = new ArrayList<>(); + if (ands == null) { + ands = new ArrayList<>(); + } ands.add(filter); return this; } @@ -105,8 +109,12 @@ public final class ClassFilter { public final Set> getFilterEntrys() { List> list = new ArrayList<>(); list.addAll(entrys); - if (ors != null) ors.forEach(f -> list.addAll(f.getFilterEntrys())); - if (ands != null) ands.forEach(f -> list.addAll(f.getFilterEntrys())); + if (ors != null) { + ors.forEach(f -> list.addAll(f.getFilterEntrys())); + } + if (ands != null) { + ands.forEach(f -> list.addAll(f.getFilterEntrys())); + } Collections.sort(list); return new LinkedHashSet<>(list); } @@ -119,8 +127,12 @@ public final class ClassFilter { public final Set> getFilterExpectEntrys() { List> list = new ArrayList<>(); list.addAll(expectEntrys); - if (ors != null) ors.forEach(f -> list.addAll(f.getFilterExpectEntrys())); - if (ands != null) ands.forEach(f -> list.addAll(f.getFilterExpectEntrys())); + if (ors != null) { + ors.forEach(f -> list.addAll(f.getFilterExpectEntrys())); + } + if (ands != null) { + ands.forEach(f -> list.addAll(f.getFilterExpectEntrys())); + } Collections.sort(list); return new LinkedHashSet<>(list); } @@ -173,7 +185,9 @@ public final class ClassFilter { ClassFilter cf = r ? this : null; if (r && ands != null) { for (ClassFilter filter : ands) { - if (!filter.accept(property, clazzname)) return; + if (!filter.accept(property, clazzname)) { + return; + } } } if (!r && ors != null) { @@ -185,10 +199,14 @@ public final class ClassFilter { } } } - if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) return; + if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) { + return; + } try { Class clazz = classLoader.loadClass(clazzname); - if (!cf.accept(property, clazz, autoScan)) return; + if (!cf.accept(property, clazz, autoScan)) { + return; + } if (cf.conf != null) { if (property == null) { property = cf.conf; @@ -217,7 +235,9 @@ public final class ClassFilter { && !clazzname.startsWith("org.redkale") && (clazzname.contains("Service") || clazzname.contains("Servlet"))) { if (cfe instanceof NoClassDefFoundError) { String msg = ((NoClassDefFoundError) cfe).getMessage(); - if (msg.startsWith("java.lang.NoClassDefFoundError: java") || msg.startsWith("javax/")) return; + if (msg.startsWith("java.lang.NoClassDefFoundError: java") || msg.startsWith("javax/")) { + return; + } } //&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) { logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe); @@ -248,30 +268,46 @@ public final class ClassFilter { boolean r = accept0(property, classname); if (r && ands != null) { for (ClassFilter filter : ands) { - if (!filter.accept(property, classname)) return false; + if (!filter.accept(property, classname)) { + return false; + } } } if (!r && ors != null) { for (ClassFilter filter : ors) { - if (filter.accept(filter.conf, classname)) return true; + if (filter.accept(filter.conf, classname)) { + return true; + } } } return r; } private boolean accept0(AnyValue property, String classname) { - if (this.refused) return false; - if (this.privilegeIncludes != null && this.privilegeIncludes.contains(classname)) return true; - if (this.privilegeExcludes != null && this.privilegeExcludes.contains(classname)) return false; - if (classname.startsWith("java.") || classname.startsWith("javax.")) return false; + if (this.refused) { + return false; + } + if (this.privilegeIncludes != null && this.privilegeIncludes.contains(classname)) { + return true; + } + if (this.privilegeExcludes != null && this.privilegeExcludes.contains(classname)) { + return false; + } + if (classname.startsWith("java.") || classname.startsWith("javax.")) { + return false; + } if (excludePatterns != null) { for (Pattern reg : excludePatterns) { - if (reg.matcher(classname).matches()) return false; + if (reg.matcher(classname).matches()) { + return false; + } } } if (includePatterns != null) { for (Pattern reg : includePatterns) { - if (reg.matcher(classname).matches()) return true; + if (reg.matcher(classname).matches()) { + return true; + } } } return includePatterns == null; @@ -288,27 +324,41 @@ public final class ClassFilter { */ @SuppressWarnings("unchecked") public boolean accept(AnyValue property, Class clazz, boolean autoscan) { - if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false; - if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false; + if (this.refused || !Modifier.isPublic(clazz.getModifiers())) { + return false; + } + if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) { + return false; + } boolean rs = superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz)); if (rs && this.excludeSuperClasses != null && this.excludeSuperClasses.length > 0) { for (Class c : this.excludeSuperClasses) { - if (c != null && (clazz == c || c.isAssignableFrom(clazz))) return false; + if (c != null && (clazz == c || c.isAssignableFrom(clazz))) { + return false; + } } } return rs; } public static Pattern[] toPattern(String[] regs) { - if (regs == null || regs.length == 0) return null; + if (regs == null || regs.length == 0) { + return null; + } int i = 0; Pattern[] rs = new Pattern[regs.length]; for (String reg : regs) { - if (reg == null || reg.trim().isEmpty()) continue; + if (reg == null || reg.trim().isEmpty()) { + continue; + } rs[i++] = Pattern.compile(reg.trim()); } - if (i == 0) return null; - if (i == rs.length) return rs; + if (i == 0) { + return null; + } + if (i == rs.length) { + return rs; + } Pattern[] ps = new Pattern[i]; System.arraycopy(rs, 0, ps, 0, i); return ps; @@ -394,7 +444,7 @@ public final class ClassFilter { */ public static final class FilterEntry implements Comparable> { - private final HashSet groups = new LinkedHashSet<>(); + private final String group; //优先级高于remote属性 private final String name; @@ -412,21 +462,18 @@ public final class ClassFilter { public FilterEntry(Class type, final boolean autoload, boolean expect, AnyValue property) { this.type = type; - String str = property == null ? null : property.getValue("groups"); - if (str != null) { - str = str.trim(); - if (str.endsWith(";")) str = str.substring(0, str.length() - 1); - } - if (str != null) this.groups.addAll(Arrays.asList(str.split(";"))); this.property = property; this.autoload = autoload; this.expect = expect; + this.group = property == null ? null : property.getValue("group", "").trim(); this.name = property == null ? "" : property.getValue("name", ""); } @Override //@Priority值越大,优先级越高, 需要排前面 public int compareTo(FilterEntry o) { - if (!(o instanceof FilterEntry)) return 1; + if (!(o instanceof FilterEntry)) { + return 1; + } Priority p1 = this.type.getAnnotation(Priority.class); Priority p2 = ((FilterEntry) o).type.getAnnotation(Priority.class); return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); @@ -434,7 +481,7 @@ public final class ClassFilter { @Override public String toString() { - return this.getClass().getSimpleName() + "[type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + this.groups + "]"; + return this.getClass().getSimpleName() + "[type=" + this.type.getSimpleName() + ", name=" + name + ", group=" + this.group + "]"; } @Override @@ -444,9 +491,13 @@ public final class ClassFilter { @Override public boolean equals(Object obj) { - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - return (this.type == ((FilterEntry) obj).type && this.groups.equals(((FilterEntry) obj).groups) && this.name.equals(((FilterEntry) obj).name)); + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + return (this.type == ((FilterEntry) obj).type && this.name.equals(((FilterEntry) obj).name)); } public Class getType() { @@ -461,16 +512,16 @@ public final class ClassFilter { return property; } - public boolean containsGroup(String group) { - return groups != null && groups.contains(group); + public boolean isEmptyGroup() { + return group == null || group.isEmpty(); } - public boolean isEmptyGroups() { - return groups == null || groups.isEmpty(); + public String getGroup() { + return group; } - public HashSet getGroups() { - return groups; + public boolean isRemote() { + return "$remote".equalsIgnoreCase(group); } public boolean isAutoload() { @@ -512,7 +563,9 @@ public final class ClassFilter { final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null; final Pattern[] excludePatterns = toPattern(excludeRegs); for (URL url : loader.getAllURLs()) { - if (exurl != null && exurl.sameFile(url)) continue; + if (exurl != null && exurl.sameFile(url)) { + continue; + } if (excludePatterns != null && url != RedkaleClassLoader.URL_NONE) { boolean skip = false; for (Pattern p : excludePatterns) { @@ -521,7 +574,9 @@ public final class ClassFilter { break; } } - if (skip) continue; + if (skip) { + continue; + } } if (url.getPath().endsWith(".jar")) { urljares.add(url); @@ -542,18 +597,36 @@ public final class ClassFilter { String entryname = it.nextElement().getName().replace('/', '.'); if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) { String classname = entryname.substring(0, entryname.length() - 6); - if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue; + if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) { + continue; + } //常见的jar跳过 - if (classname.startsWith("com.redkaledyn.")) break; //redkale动态生成的类 - if (classname.startsWith("com.mysql.")) break; - if (classname.startsWith("org.mariadb.")) break; - if (classname.startsWith("oracle.jdbc.")) break; - if (classname.startsWith("org.postgresql.")) break; - if (classname.startsWith("com.microsoft.sqlserver.")) break; + if (classname.startsWith("com.redkaledyn.")) { + break; //redkale动态生成的类 + } + if (classname.startsWith("com.mysql.")) { + break; + } + if (classname.startsWith("org.mariadb.")) { + break; + } + if (classname.startsWith("oracle.jdbc.")) { + break; + } + if (classname.startsWith("org.postgresql.")) { + break; + } + if (classname.startsWith("com.microsoft.sqlserver.")) { + break; + } classes.add(classname); - if (debug) debugstr.append(classname).append("\r\n"); + if (debug) { + debugstr.append(classname).append("\r\n"); + } for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); + if (filter != null) { + filter.filter(null, classname, url); + } } } } @@ -562,7 +635,9 @@ public final class ClassFilter { } else { for (String classname : classes) { for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); + if (filter != null) { + filter.filter(null, classname, url); + } } } } @@ -572,7 +647,9 @@ public final class ClassFilter { if (classes == null) { classes = new LinkedHashSet<>(); final Set cs = classes; - if (url == RedkaleClassLoader.URL_NONE) loader.forEachCacheClass(v -> cs.add(v)); + if (url == RedkaleClassLoader.URL_NONE) { + loader.forEachCacheClass(v -> cs.add(v)); + } if (cs.isEmpty()) { files.clear(); File root = new File(url.getFile()); @@ -580,17 +657,25 @@ public final class ClassFilter { loadClassFiles(excludeFile, root, files); for (File f : files) { String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.'); - if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue; + if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) { + continue; + } classes.add(classname); - if (debug) debugstr.append(classname).append("\r\n"); + if (debug) { + debugstr.append(classname).append("\r\n"); + } for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); + if (filter != null) { + filter.filter(null, classname, url); + } } } } else { for (String classname : classes) { for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); + if (filter != null) { + filter.filter(null, classname, url); + } } } } @@ -598,7 +683,9 @@ public final class ClassFilter { } else { for (String classname : classes) { for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); + if (filter != null) { + filter.filter(null, classname, url); + } } } } @@ -610,9 +697,13 @@ public final class ClassFilter { if (root.isFile() && root.getName().endsWith(".class")) { files.add(root); } else if (root.isDirectory()) { - if (exclude != null && exclude.equals(root)) return; + if (exclude != null && exclude.equals(root)) { + return; + } File[] lfs = root.listFiles(); - if (lfs == null) throw new RedkaleException("File(" + root + ") cannot listFiles()"); + if (lfs == null) { + throw new RedkaleException("File(" + root + ") cannot listFiles()"); + } for (File f : lfs) { loadClassFiles(exclude, f, files); } diff --git a/src/main/java/org/redkale/boot/NodeHttpServer.java b/src/main/java/org/redkale/boot/NodeHttpServer.java index bc583ab29..ba901dc1c 100644 --- a/src/main/java/org/redkale/boot/NodeHttpServer.java +++ b/src/main/java/org/redkale/boot/NodeHttpServer.java @@ -151,7 +151,7 @@ public class NodeHttpServer extends NodeServer { } catch (Exception ex) { logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex); } - nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set) null, (AnyValue) null); + nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, application.getResourceFactory(), application.getSncpRpcGroups(), sncpClient, messageAgent, (String) null, (AnyValue) null); regFactory.register(resourceName, WebSocketNode.class, nodeService); } resourceFactory.inject(resourceName, nodeService, self); @@ -247,7 +247,7 @@ public class NodeHttpServer extends NodeServer { for (int i = 0; i < mappings.length; i++) { mappings[i] = pref + mappings[i]; } - ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings)); + ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings)); } } final CopyOnWriteArrayList> rests = sb == null ? null : new CopyOnWriteArrayList<>(); @@ -265,7 +265,7 @@ public class NodeHttpServer extends NodeServer { int maxNameLength = 0; if (rests != null) { for (AbstractMap.SimpleEntry en : rests) { - int pos = en.getKey().indexOf('#'); + int pos = en.getKey().indexOf(':'); if (pos > maxTypeLength) { maxTypeLength = pos; } @@ -277,7 +277,7 @@ public class NodeHttpServer extends NodeServer { } if (webss != null) { for (AbstractMap.SimpleEntry en : webss) { - int pos = en.getKey().indexOf('#'); + int pos = en.getKey().indexOf(':'); if (pos > maxTypeLength) { maxTypeLength = pos; } @@ -290,32 +290,34 @@ public class NodeHttpServer extends NodeServer { if (rests != null) { for (AbstractMap.SimpleEntry en : rests) { StringBuilder sub = new StringBuilder(); - int pos = en.getKey().indexOf('#'); - sub.append("RestDynServlet (type=").append(en.getKey().substring(0, pos)); + int pos = en.getKey().indexOf(':'); + sub.append("RestServlet (type=").append(en.getKey().substring(0, pos)); for (int i = 0; i < maxTypeLength - pos; i++) { sub.append(' '); } - sub.append(", name='").append(en.getKey().substring(pos + 1)); - for (int i = 0; i < maxNameLength - pos; i++) { + String n = en.getKey().substring(pos + 1); + sub.append(", name='").append(n).append("'"); + for (int i = 0; i < maxNameLength - n.length(); i++) { sub.append(' '); } - sub.append("')"); + sub.append(")"); ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue())); } } if (webss != null) { for (AbstractMap.SimpleEntry en : webss) { StringBuilder sub = new StringBuilder(); - int pos = en.getKey().indexOf('#'); + int pos = en.getKey().indexOf(':'); sub.append("RestWebSocket (type=").append(en.getKey().substring(0, pos)); for (int i = 0; i < maxTypeLength - pos; i++) { sub.append(' '); } - sub.append(", name='").append(en.getKey().substring(pos + 1)); - for (int i = 0; i < maxNameLength - pos; i++) { + String n = en.getKey().substring(pos + 1); + sub.append(", name='").append(n).append("'"); + for (int i = 0; i < maxNameLength - n.length(); i++) { sub.append(' '); } - sub.append("')"); + sub.append(")"); ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue())); } } @@ -422,7 +424,7 @@ public class NodeHttpServer extends NodeServer { } HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix); if (servlet == null) { - return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null + return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null } String prefix2 = prefix; WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); @@ -440,7 +442,7 @@ public class NodeHttpServer extends NodeServer { for (int i = 0; i < mappings.length; i++) { mappings[i] = prefix2 + mappings[i]; } - rests.add(new AbstractMap.SimpleEntry<>(Sncp.getResourceType(service).getName() + "#" + name, mappings)); + rests.add(new AbstractMap.SimpleEntry<>(Sncp.getResourceType(service).getName() + ":" + name, mappings)); } } finally { scdl.countDown(); @@ -510,7 +512,7 @@ public class NodeHttpServer extends NodeServer { for (int i = 0; i < mappings.length; i++) { mappings[i] = prefix2 + mappings[i]; } - webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + "#" + rs.name(), mappings)); + webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + ":" + rs.name(), mappings)); } } } diff --git a/src/main/java/org/redkale/boot/NodeServer.java b/src/main/java/org/redkale/boot/NodeServer.java index 5d1fbb59d..98ce75513 100644 --- a/src/main/java/org/redkale/boot/NodeServer.java +++ b/src/main/java/org/redkale/boot/NodeServer.java @@ -62,18 +62,6 @@ public abstract class NodeServer { protected final Thread serverThread; - //当前Server的SNCP协议的组 - protected String sncpGroup = null; - - //SNCP服务的Client - private SncpClient sncpClient; - - //SncpClient的AsyncGroup - private AsyncIOGroup sncpAsyncGroup; - - //SNCP服务的地址, 非SNCP为null - private InetSocketAddress sncpAddress; - //加载Service时的处理函数 protected BiConsumer consumer; @@ -94,6 +82,7 @@ public abstract class NodeServer { //远程模式的Service对象集合 protected final Set remoteServices = new LinkedHashSet<>(); + //存在SncpServlet、RestServlet protected final Map dynServletMap = new LinkedHashMap<>(); //MessageAgent对象集合 @@ -102,6 +91,18 @@ public abstract class NodeServer { //需要远程模式Service的MessageAgent对象集合 protected final Map sncpRemoteAgents = new HashMap<>(); + //当前Server的SNCP协议的组 + protected String sncpGroup = null; + + //当前Server的SNCP服务Client + protected SncpClient sncpClient; + + //SncpClient的AsyncGroup + private AsyncIOGroup sncpAsyncGroup; + + //SNCP服务的地址, 非SNCP为null + private InetSocketAddress sncpAddress; + private volatile int maxTypeLength = 0; private volatile int maxNameLength = 0; @@ -136,7 +137,7 @@ public abstract class NodeServer { if (isSNCP()) { // SNCP协议 String host = this.serverConf.getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0").replace("0.0.0.0", ""); this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getAddress().getHostAddress() : host, this.serverConf.getIntValue("port")); - this.sncpGroup = application.getSncpTransportFactory().findGroupName(this.sncpAddress); + this.sncpGroup = application.getSncpRpcGroups().getGroup(this.sncpAddress); //单向SNCP服务不需要对等group //if (this.sncpGroup == null) throw new RedkaleException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found info"); } @@ -170,15 +171,10 @@ public abstract class NodeServer { server.init(this.serverConf); if (this.sncpAddress != null) { //初始化SncpClient this.sncpAsyncGroup = new AsyncIOGroup(true, "Redkale-SncpClient-IOThread-%s", application.getWorkExecutor(), server.getBufferCapacity(), server.getBufferPoolSize()).skipClose(true); - this.sncpClient = new SncpClient(server.getName(), this.sncpAsyncGroup, this.sncpAddress, new ClientAddress(sncpAddress), server.getNetprotocol(), Utility.cpus(), 1000); + this.sncpClient = new SncpClient(server.getName(), this.sncpAsyncGroup, this.sncpAddress, new ClientAddress(this.sncpAddress), server.getNetprotocol(), Utility.cpus(), 1000); } - //init之后才有Executor - //废弃 @since 2.3.0 -// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, Executor.class, server.getWorkExecutor()); -// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ExecutorService.class, server.getWorkExecutor()); -// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ThreadPoolExecutor.class, server.getWorkExecutor()); - initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。 + initResource(); //给DataSource、CacheSource注册依赖注入时的监听回调事件。 String interceptorClass = this.serverConf.getValue("interceptor", ""); if (!interceptorClass.isEmpty()) { Class clazz = serverClassLoader.loadClass(interceptorClass); @@ -229,7 +225,6 @@ public abstract class NodeServer { final NodeServer self = this; //--------------------------------------------------------------------------------------------- final ResourceFactory appResFactory = application.getResourceFactory(); - final TransportFactory appSncpTranFactory = application.getSncpTransportFactory(); final String confURI = appResFactory.find(RESNAME_APP_CONF_DIR, String.class); //------------------------------------- 注册 Resource -------------------------------------------------------- resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> { @@ -302,10 +297,7 @@ public abstract class NodeServer { } //ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory); - 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); + Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, appResFactory, application.getSncpRpcGroups(), sncpClient, null, null, null); appResFactory.register(resourceName, resServiceType, service); field.set(srcObj, service); @@ -350,23 +342,13 @@ public abstract class NodeServer { if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { return null; //远程模式不需要注入 CacheSource } - if (!(srcObj instanceof Service)) { - throw new RedkaleException("CacheSource must be inject in Service, cannot in " + srcObj); + if (srcObj instanceof Servlet) { + throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj); } - final Service srcService = (Service) srcObj; - 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); CacheSource source = application.loadCacheSource(resourceName, ws); field.set(srcObj, source); - if (ws && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource - NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr); - if (sncpServer != null && source != null && source.getClass().getAnnotation(Local.class) == null) { //本地模式的Service不生成SncpServlet - sncpServer.getSncpServer().addSncpServlet((Service) source); - } - } logger.info("Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')"); return source; } catch (Exception e) { @@ -392,33 +374,17 @@ public abstract class NodeServer { if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) { return null; //远程模式不需要注入 WebSocketNode } - Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class); - MessageAgent messageAgent = null; - if (srcObj instanceof Service) { - messageAgent = Sncp.getMessageAgent((Service) srcObj); - } else if (srcObj instanceof WebSocketServlet) { - try { - Field c = WebSocketServlet.class.getDeclaredField("messageAgent"); - RedkaleClassLoader.putReflectionField("messageAgent", c); - c.setAccessible(true); - messageAgent = (MessageAgent) c.get(srcObj); - } catch (Exception ex) { - logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex); - } - } + Service nodeService = rf.find(resourceName, WebSocketNode.class); if (nodeService == null) { final HashSet groups = new HashSet<>(); if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) { groups.add(NodeServer.this.sncpGroup); } - nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null); + nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, application.getResourceFactory(), application.getSncpRpcGroups(), sncpClient, null, (String) null, (AnyValue) null); (isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService); ((org.redkale.net.http.WebSocketNodeService) nodeService).setName(resourceName); } resourceFactory.inject(resourceName, nodeService, self); - if (messageAgent != null && Sncp.getMessageAgent(nodeService) == null) { - Sncp.setMessageAgent(nodeService, messageAgent); - } field.set(srcObj, nodeService); if (Sncp.isRemote(nodeService)) { remoteServices.add(nodeService); @@ -453,7 +419,7 @@ public abstract class NodeServer { final Set> entrys = (Set) serviceFilter.getAllFilterEntrys(); ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory; final ResourceFactory appResourceFactory = application.getResourceFactory(); - final TransportFactory appSncpTransFactory = application.getSncpTransportFactory(); + final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); final AtomicInteger serviceCount = new AtomicInteger(); for (FilterEntry entry : entrys) { //service实现类 final Class serviceImplClass = entry.getType(); @@ -480,6 +446,9 @@ public abstract class NodeServer { if (entry.getName().contains("$")) { throw new RedkaleException(" value cannot contains '$' in " + entry.getProperty()); } + if (!entry.isEmptyGroup() && !entry.isRemote() && rpcGroups.containsGroup(entry.getGroup())) { + throw new RedkaleException("Not found group(" + entry.getGroup() + ")"); + } Service oldother = resourceFactory.find(entry.getName(), serviceImplClass); if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。 if (!Sncp.isRemote(oldother)) { @@ -487,16 +456,9 @@ public abstract class NodeServer { } continue; } - final HashSet groups = entry.getGroups(); //groups.isEmpty()表示没有配置groups属性。 - if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) { - groups.add(this.sncpGroup); - } - - final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !serviceImplClass.isInterface() && !Modifier.isAbstract(serviceImplClass.getModifiers())) //非SNCP的Server,通常是单点服务 - || groups.contains(this.sncpGroup) //本地IP含在内的 - || (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置 - || serviceImplClass.getAnnotation(Local.class) != null;//本地模式 - if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) { + final String group = rpcGroups.isLocalGroup(this.sncpGroup, this.sncpAddress, entry) ? null : entry.getGroup(); + final boolean localMode = rpcGroups.isLocalGroup(this.sncpGroup, this.sncpAddress, entry) || serviceImplClass.getAnnotation(Local.class) != null;//本地模式 + if (localMode && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) { continue; //本地模式不能实例化接口和抽象类的Service类 } final ResourceTypeLoader resourceLoader = (ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) -> { @@ -509,32 +471,19 @@ public abstract class NodeServer { return null; } RedkaleClassLoader.putReflectionPublicMethods(serviceImplClass.getName()); - MessageAgent agent = null; - if (entry.getProperty() != null && entry.getProperty().getValue("mq") != null) { - agent = application.getMessageAgent(entry.getProperty().getValue("mq")); - if (agent != null) { - messageAgents.put(agent.getName(), agent); - } - } - + MessageAgent agent = getMessageAgent(entry.getProperty()); Service service; final boolean ws = srcObj instanceof WebSocketServlet; - if (ws || localed) { //本地模式 - service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, agent, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty()); + if (ws || localMode) { //本地模式 + service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, appResourceFactory, rpcGroups, this.sncpClient, agent, group, entry.getProperty()); } else { - service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, agent, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty()); - } - if (service instanceof org.redkale.net.http.WebSocketNodeService) { - ((org.redkale.net.http.WebSocketNodeService) service).setName(resourceName); - if (agent != null) { - Sncp.setMessageAgent(service, agent); - } + service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appResourceFactory, rpcGroups, this.sncpClient, agent, group, entry.getProperty()); } final Class restype = Sncp.getResourceType(service); if (rf.find(resourceName, restype) == null) { regFactory.register(resourceName, restype, service); } else if (isSNCP() && !entry.isAutoload()) { - throw new RedkaleException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + resourceName + ", group:" + groups + ") is repeat."); + throw new RedkaleException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + resourceName + ", group:" + group + ") is repeat."); } if (Sncp.isRemote(service)) { remoteServices.add(service); @@ -656,6 +605,17 @@ public abstract class NodeServer { maxTypeLength = Math.max(maxTypeLength, Sncp.getResourceType(y).getName().length() + 1); } + protected MessageAgent getMessageAgent(AnyValue serviceConf) { + MessageAgent agent = null; + if (serviceConf != null && serviceConf.getValue("mq") != null) { + agent = application.getMessageAgent(serviceConf.getValue("mq")); + if (agent != null) { + messageAgents.put(agent.getName(), agent); + } + } + return agent; + } + //Service.init执行之前调用 protected void preInitServices(Set localServices, Set remoteServices) { final ClusterAgent cluster = application.getClusterAgent(); @@ -730,13 +690,10 @@ public abstract class NodeServer { cf = null; for (AnyValue list : proplist) { AnyValue.DefaultAnyValue prop = null; - String sc = list.getValue("groups"); + String sc = list.getValue("group"); String mq = list.getValue("mq"); if (sc != null) { sc = sc.trim(); - if (sc.endsWith(";")) { - sc = sc.substring(0, sc.length() - 1); - } } if (sc == null) { sc = localGroup; @@ -744,7 +701,7 @@ public abstract class NodeServer { if (sc != null || mq != null) { prop = new AnyValue.DefaultAnyValue(); if (sc != null) { - prop.addValue("groups", sc); + prop.addValue("group", sc); } if (mq != null) { prop.addValue("mq", mq); diff --git a/src/main/java/org/redkale/boot/NodeSncpServer.java b/src/main/java/org/redkale/boot/NodeSncpServer.java index a4f625b0d..e8ef371c4 100644 --- a/src/main/java/org/redkale/boot/NodeSncpServer.java +++ b/src/main/java/org/redkale/boot/NodeSncpServer.java @@ -37,7 +37,7 @@ public class NodeSncpServer extends NodeServer { if (x.getClass().getAnnotation(Local.class) != null) { return; //本地模式的Service不生成SncpServlet } - SncpDynServlet servlet = sncpServer.addSncpServlet(x); + SncpServlet servlet = sncpServer.addSncpServlet(x); dynServletMap.put(x, servlet); if (agent != null) { agent.putService(this, x, servlet); @@ -74,9 +74,16 @@ public class NodeSncpServer extends NodeServer { final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null; List servlets = sncpServer.getSncpServlets(); Collections.sort(servlets); + + int maxTypeLength = 0; + int maxNameLength = 0; + for (SncpServlet en : servlets) { + maxNameLength = Math.max(maxNameLength, en.getServiceName().length() + 1); + maxTypeLength = Math.max(maxTypeLength, en.getServiceType().getName().length()); + } for (SncpServlet en : servlets) { if (sb != null) { - sb.append("Load ").append(en).append(LINE_SEPARATOR); + sb.append("Load ").append(toSimpleString(en, maxTypeLength, maxNameLength)).append(LINE_SEPARATOR); } } if (sb != null && sb.length() > 0) { @@ -84,6 +91,24 @@ public class NodeSncpServer extends NodeServer { } } + private StringBuilder toSimpleString(SncpServlet servlet, int maxTypeLength, int maxNameLength) { + StringBuilder sb = new StringBuilder(); + Class serviceType = servlet.getServiceType(); + String serviceName = servlet.getServiceName(); + int size = servlet.getActionSize(); + sb.append(SncpServlet.class.getSimpleName()).append(" (type=").append(serviceType.getName()); + int len = maxTypeLength - serviceType.getName().length(); + for (int i = 0; i < len; i++) { + sb.append(' '); + } + sb.append(", serviceid=").append(servlet.getServiceid()).append(", name='").append(serviceName).append("'"); + for (int i = 0; i < maxNameLength - serviceName.length(); i++) { + sb.append(' '); + } + sb.append(", actions.size=").append(size > 9 ? "" : " ").append(size).append(")"); + return sb; + } + @Override public boolean isSNCP() { return true; @@ -126,7 +151,6 @@ 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()); } @Override diff --git a/src/main/java/org/redkale/boot/watch/TransportWatchService.java b/src/main/java/org/redkale/boot/watch/TransportWatchService.java deleted file mode 100644 index a21d4053b..000000000 --- a/src/main/java/org/redkale/boot/watch/TransportWatchService.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.boot.watch; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.AsynchronousSocketChannel; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; -import org.redkale.annotation.*; -import org.redkale.boot.Application; -import org.redkale.net.*; -import org.redkale.net.http.*; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.util.AnyValue; -import org.redkale.util.AnyValue.DefaultAnyValue; - -/** - * - * @author zhangjx - */ -@RestService(name = "transport", catalog = "watch", repair = false) -public class TransportWatchService extends AbstractWatchService { - - @Comment("不存在的Group节点") - public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001; - - @Comment("非法的Node节点IP地址") - public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002; - - @Comment("Node节点IP地址已存在") - public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003; - - protected final ReentrantLock lock = new ReentrantLock(); - - @Resource - protected Application application; - - @Resource - protected TransportFactory transportFactory; - - @RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点") - public List listNodes() { - return transportFactory.getGroupInfos(); - } - - @RestMapping(name = "addnode", auth = false, comment = "动态增加指定Group的Node节点") - public RetResult addNode(@RestParam(name = "group", comment = "Group节点名") final String group, - @RestParam(name = "addr", comment = "节点IP") final String addr, - @RestParam(name = "port", comment = "节点端口") final int port) throws IOException { - InetSocketAddress address; - try { - address = new InetSocketAddress(addr, port); - AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(); - channel.connect(address).get(2, TimeUnit.SECONDS); //连接超时2秒 - channel.close(); - } catch (Exception e) { - return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect"); - } - if (transportFactory.findGroupName(address) != null) { - return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists"); - } - lock.lock(); - try { - if (transportFactory.findGroupInfo(group) == null) { - return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); - } - transportFactory.addGroupInfo(group, address); - for (Service service : transportFactory.getServices()) { - if (!Sncp.isSncpDyn(service)) { - continue; - } - OldSncpClient client = Sncp.getSncpOldClient(service); - if (Sncp.isRemote(service)) { - if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { - client.getRemoteGroupTransport().addRemoteAddresses(address); - } - } - } - DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port); - for (AnyValue groupconf : application.getAppConfig().getAnyValues("group")) { - if (group.equals(groupconf.getValue("name"))) { - ((DefaultAnyValue) groupconf).addValue("node", node); - break; - } - } - //application.restoreConfig(); - } finally { - lock.unlock(); - } - return RetResult.success(); - } - - @RestMapping(name = "removenode", auth = false, comment = "动态删除指定Group的Node节点") - public RetResult removeNode(@RestParam(name = "group", comment = "Group节点名") final String group, - @RestParam(name = "addr", comment = "节点IP") final String addr, - @RestParam(name = "port", comment = "节点端口") final int port) throws IOException { - if (group == null) { - return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); - } - final InetSocketAddress address = new InetSocketAddress(addr, port); - if (!group.equals(transportFactory.findGroupName(address))) { - return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")"); - } - lock.lock(); - try { - if (transportFactory.findGroupInfo(group) == null) { - return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); - } - transportFactory.removeGroupInfo(group, address); - for (Service service : transportFactory.getServices()) { - if (!Sncp.isSncpDyn(service)) { - continue; - } - OldSncpClient client = Sncp.getSncpOldClient(service); - if (Sncp.isRemote(service)) { - if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { - client.getRemoteGroupTransport().removeRemoteAddresses(address); - } - } - } - for (AnyValue groupconf : application.getAppConfig().getAnyValues("group")) { - if (group.equals(groupconf.getValue("name"))) { - ((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port)); - break; - } - } - //application.restoreConfig(); - } finally { - lock.unlock(); - } - return RetResult.success(); - } - - @RestMapping(name = "test1", auth = false, comment = "预留") - public RetResult test1() { - return RetResult.success(); - } - - @RestMapping(name = "test2", auth = false, comment = "预留") - public RetResult test2() { - return RetResult.success(); - } - - @RestMapping(name = "test3", auth = false, comment = "预留") - public RetResult test3() { - return RetResult.success(); - } - - @RestMapping(name = "test4", auth = false, comment = "预留") - public RetResult test4() { - return RetResult.success(); - } -} diff --git a/src/main/java/org/redkale/cluster/ClusterAgent.java b/src/main/java/org/redkale/cluster/ClusterAgent.java index 8f0e97dd1..13c2487ba 100644 --- a/src/main/java/org/redkale/cluster/ClusterAgent.java +++ b/src/main/java/org/redkale/cluster/ClusterAgent.java @@ -60,8 +60,6 @@ public abstract class ClusterAgent { protected Set tags; - protected TransportFactory transportFactory; - protected final ConcurrentHashMap localEntrys = new ConcurrentHashMap<>(); protected final ConcurrentHashMap remoteEntrys = new ConcurrentHashMap<>(); @@ -245,7 +243,7 @@ public abstract class ClusterAgent { return; } Collection addrs = ClusterAgent.this.queryAddress(entry).join(); - Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netProtocol, entry.address, null, addrs); + //Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netProtocol, entry.address, null, addrs); } protected String urlEncode(String value) { @@ -329,14 +327,6 @@ public abstract class ClusterAgent { return remoteEntrys; } - public TransportFactory getTransportFactory() { - return transportFactory; - } - - public void setTransportFactory(TransportFactory transportFactory) { - this.transportFactory = transportFactory; - } - public String getName() { return name; } diff --git a/src/main/java/org/redkale/convert/Convert.java b/src/main/java/org/redkale/convert/Convert.java index 2fb24a8ec..166ffa750 100644 --- a/src/main/java/org/redkale/convert/Convert.java +++ b/src/main/java/org/redkale/convert/Convert.java @@ -59,6 +59,7 @@ public abstract class Convert { public abstract void offerReader(final R reader); + //返回的Writer子类必须实现ByteTuple接口 public abstract W pollWriter(); public abstract void offerWriter(final W write); diff --git a/src/main/java/org/redkale/net/Server.java b/src/main/java/org/redkale/net/Server.java index fe9e350ee..0ec190aa6 100644 --- a/src/main/java/org/redkale/net/Server.java +++ b/src/main/java/org/redkale/net/Server.java @@ -7,12 +7,12 @@ package org.redkale.net; import java.io.*; import java.net.*; -import java.nio.charset.*; +import java.nio.charset.Charset; import java.util.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.atomic.LongAdder; import java.util.logging.*; -import javax.net.ssl.*; -import org.redkale.boot.*; +import javax.net.ssl.SSLContext; +import org.redkale.boot.Application; import static org.redkale.net.AsyncGroup.UDP_BUFFER_CAPACITY; import org.redkale.net.Filter; import org.redkale.util.*; @@ -315,10 +315,14 @@ public abstract class Server, R extends ClientR protected final LongAdder respDoneCounter = new LongAdder(); - protected final AtomicLong connIndexSeq = new AtomicLong(); - - private final AtomicInteger connSeqno = new AtomicInteger(); - private final AtomicBoolean closed = new AtomicBoolean(); protected ScheduledFuture timeoutFuture; - protected ClientConnection[] connArray; //连接池 + //连随机地址模式 + final AtomicLong connIndexSeq = new AtomicLong(); - protected LongAdder[] connRespWaitings; //连接当前处理数 + //连随机地址模式 + final ClientConnection[] connArray; //连接池 - protected AtomicBoolean[] connOpenStates; //conns的标记组,当conn不存在或closed状态,标记为false + //连随机地址模式 + final LongAdder[] connRespWaitings; //连接当前处理数 - protected final Queue>[] connAcquireWaitings; //连接等待池 + //连随机地址模式 + final AtomicBoolean[] connOpenStates; //conns的标记组,当conn不存在或closed状态,标记为false - protected int connLimit = Utility.cpus(); //最大连接数 + //连随机地址模式 + final int connLimit; //最大连接数 + + //连随机地址模式 + private final Queue>[] connAcquireWaitings; //连接等待池 + + //连指定地址模式 + final ConcurrentHashMap connAddrEntrys = new ConcurrentHashMap<>(); protected int maxPipelines = DEFAULT_MAX_PIPELINES; //单个连接最大并行处理数 @@ -133,7 +141,7 @@ public abstract class Client, R extends ClientR for (int i = 0; i < connOpenStates.length; i++) { this.connOpenStates[i] = new AtomicBoolean(); this.connRespWaitings[i] = new LongAdder(); - this.connAcquireWaitings[i] = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 10) : new ConcurrentLinkedDeque(); + this.connAcquireWaitings[i] = new ConcurrentLinkedDeque(); } //timeoutScheduler 不仅仅给超时用, 还给write用 this.timeoutScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { @@ -198,6 +206,23 @@ public abstract class Client, R extends ClientR conn.dispose(null); } } + for (AddressConnEntry entry : this.connAddrEntrys.values()) { + ClientConnection conn = entry.connection; + if (conn == null) { + continue; + } + final R closeReq = closeRequestSupplier == null ? null : closeRequestSupplier.get(); + if (closeReq == null) { + conn.dispose(null); + } else { + try { + conn.writeChannel(closeReq).get(1, TimeUnit.SECONDS); + } catch (Exception e) { + } + conn.dispose(null); + } + } + this.connAddrEntrys.clear(); group.close(); } } @@ -216,6 +241,20 @@ public abstract class Client, R extends ClientR return connect().thenCompose(conn -> writeChannel(conn, request, respTransfer)); } + public final CompletableFuture

sendAsync(SocketAddress addr, R request) { + if (request.workThread == null) { + request.workThread = WorkThread.currWorkThread(); + } + return connect(addr).thenCompose(conn -> writeChannel(conn, request)); + } + + public final CompletableFuture sendAsync(SocketAddress addr, R request, Function respTransfer) { + if (request.workThread == null) { + request.workThread = WorkThread.currWorkThread(); + } + return connect(addr).thenCompose(conn -> writeChannel(conn, request, respTransfer)); + } + protected CompletableFuture

writeChannel(ClientConnection conn, R request) { return conn.writeChannel(request); } @@ -233,7 +272,7 @@ public abstract class Client, R extends ClientR } final Queue> waitQueue = this.connAcquireWaitings[connIndex]; if (this.connOpenStates[connIndex].compareAndSet(false, true)) { - CompletableFuture future = address.createClient(tcp, group, readTimeoutSeconds, writeTimeoutSeconds) + CompletableFuture future = group.createClient(tcp, this.address.randomAddress(), readTimeoutSeconds, writeTimeoutSeconds) .thenApply(c -> (C) createClientConnection(connIndex, c).setMaxPipelines(maxPipelines)); R virtualReq = createVirtualRequestAfterConnect(); if (virtualReq != null) { @@ -249,7 +288,9 @@ public abstract class Client, R extends ClientR this.connArray[connIndex] = c; CompletableFuture f; while ((f = waitQueue.poll()) != null) { - f.complete(c); + if (!f.isDone()) { + f.complete(c); + } } return c; }).whenComplete((r, t) -> { @@ -262,35 +303,51 @@ public abstract class Client, R extends ClientR waitQueue.offer(rs); return rs; } -// } -// ClientConnection minRunningConn = null; -// for (int i = 0; i < size; i++) { -// final int index = i; -// final ClientConnection conn = this.connArray[index]; -// if (conn == null || !conn.isOpen()) { -// if (this.connOpenStates[index].compareAndSet(false, true)) { -// CompletableFuture future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds) -// .thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines)); -// return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> { -// c.authenticated = true; -// this.connArray[index] = c; -// return c; -// }).whenComplete((r, t) -> { -// if (t != null) this.connOpenStates[index].set(false); -// }); -// } -// } else if (conn.runningCount() < 1) { -// return CompletableFuture.completedFuture(conn); -// } else if (minRunningConn == null || minRunningConn.runningCount() > conn.runningCount()) { -// minRunningConn = conn; -// } -// } -// if (minRunningConn != null) { // && minRunningConn.runningCount() < maxPipelines -// return CompletableFuture.completedFuture(minRunningConn); -// } -// CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); -// connAcquireWaitings[connSeqno.getAndIncrement() % this.connLimit].offer(rs); -// return rs; + } + + //指定地址获取连接 + protected CompletableFuture connect(final SocketAddress addr) { + if (addr == null) { + return connect(); + } + final AddressConnEntry entry = connAddrEntrys.computeIfAbsent(addr, a -> new AddressConnEntry()); + C ec = entry.connection; + if (ec != null && ec.isOpen()) { + return CompletableFuture.completedFuture(ec); + } + final Queue> waitQueue = entry.connAcquireWaitings; + if (entry.connOpenState.compareAndSet(false, true)) { + CompletableFuture future = group.createClient(tcp, addr, readTimeoutSeconds, writeTimeoutSeconds) + .thenApply(c -> (C) createClientConnection(-1, c).setMaxPipelines(maxPipelines)); + R virtualReq = createVirtualRequestAfterConnect(); + if (virtualReq != null) { + future = future.thenCompose(conn -> conn.writeVirtualRequest(virtualReq).thenApply(v -> conn)); + } else { + future = future.thenApply(conn -> (C) conn.readChannel()); + } + if (authenticate != null) { + future = future.thenCompose(authenticate); + } + return future.thenApply(c -> { + c.setAuthenticated(true); + entry.connection = c; + CompletableFuture f; + while ((f = waitQueue.poll()) != null) { + if (!f.isDone()) { + f.complete(c); + } + } + return c; + }).whenComplete((r, t) -> { + if (t != null) { + entry.connOpenState.set(false); + } + }); + } else { + CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); + waitQueue.offer(rs); + return rs; + } } protected long getRespWaitingCount() { @@ -334,4 +391,18 @@ public abstract class Client, R extends ClientR this.writeTimeoutSeconds = writeTimeoutSeconds; } + protected static class AddressConnEntry { + + public C connection; + + public final LongAdder connRespWaiting = new LongAdder(); + + public final AtomicBoolean connOpenState = new AtomicBoolean(); + + public final Queue> connAcquireWaitings = new ConcurrentLinkedDeque(); + + AddressConnEntry() { + } + + } } diff --git a/src/main/java/org/redkale/net/client/ClientAddress.java b/src/main/java/org/redkale/net/client/ClientAddress.java index 06e1d68c3..27815f103 100644 --- a/src/main/java/org/redkale/net/client/ClientAddress.java +++ b/src/main/java/org/redkale/net/client/ClientAddress.java @@ -6,7 +6,6 @@ import java.net.SocketAddress; import java.util.*; import java.util.concurrent.*; import org.redkale.convert.json.JsonConvert; -import org.redkale.net.*; /** * Client连接地址 @@ -61,7 +60,7 @@ public class ClientAddress implements java.io.Serializable { } } - public CompletableFuture createClient(final boolean tcp, final AsyncGroup group, int readTimeoutSeconds, int writeTimeoutSeconds) { + public SocketAddress randomAddress() { SocketAddress addr = address; if (addr == null) { SocketAddress[] addrs = this.addresses; @@ -71,7 +70,7 @@ public class ClientAddress implements java.io.Serializable { } addr = addrs[ThreadLocalRandom.current().nextInt(addrs.length)]; } - return group.createClient(tcp, addr, readTimeoutSeconds, writeTimeoutSeconds); + return addr; } private static SocketAddress[] createAddressArray(List ws) { diff --git a/src/main/java/org/redkale/net/client/ClientConnection.java b/src/main/java/org/redkale/net/client/ClientConnection.java index 3cff046cc..0ca75ba37 100644 --- a/src/main/java/org/redkale/net/client/ClientConnection.java +++ b/src/main/java/org/redkale/net/client/ClientConnection.java @@ -6,6 +6,7 @@ package org.redkale.net.client; import java.io.Serializable; +import java.net.SocketAddress; import java.nio.channels.ClosedChannelException; import java.util.*; import java.util.concurrent.*; @@ -31,7 +32,7 @@ public abstract class ClientConnection implements Co protected final Client client; - protected final LongAdder respWaitingCounter; + protected final LongAdder respWaitingCounter; //可能为null protected final LongAdder doneRequestCounter = new LongAdder(); @@ -41,6 +42,8 @@ public abstract class ClientConnection implements Co final ConcurrentLinkedQueue pauseRequests = new ConcurrentLinkedQueue<>(); + private final Client.AddressConnEntry connEntry; + protected final AsyncConnection channel; private final ClientCodec codec; @@ -64,7 +67,8 @@ public abstract class ClientConnection implements Co this.client = client; this.codec = createCodec(); this.index = index; - this.respWaitingCounter = client.connRespWaitings[index]; + this.connEntry = index >= 0 ? null : client.connAddrEntrys.get(channel.getRemoteAddress()); + this.respWaitingCounter = index >= 0 ? client.connRespWaitings[index] : this.connEntry.connRespWaiting; this.channel = channel.beforeCloseListener(this); this.writeThread = (ClientWriteIOThread) channel.getWriteIOThread(); } @@ -113,8 +117,12 @@ public abstract class ClientConnection implements Co @Override //AsyncConnection.beforeCloseListener public void accept(AsyncConnection t) { respWaitingCounter.reset(); - client.connOpenStates[index].set(false); - client.connArray[index] = null; //必须connOpenStates之后 + if (index >= 0) { + client.connOpenStates[index].set(false); + client.connArray[index] = null; //必须connOpenStates之后 + } else if (connEntry != null) { + connEntry.connOpenState.set(false); + } } public void dispose(Throwable exc) { @@ -191,6 +199,10 @@ public abstract class ClientConnection implements Co return channel; } + public SocketAddress getRemoteAddress() { + return channel.getRemoteAddress(); + } + public long getDoneRequestCounter() { return doneRequestCounter.longValue(); } diff --git a/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java b/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java index 671af3866..fcd145983 100644 --- a/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java +++ b/src/main/java/org/redkale/net/http/HttpDispatcherServlet.java @@ -5,17 +5,17 @@ */ package org.redkale.net.http; -import java.io.*; +import java.io.IOException; import java.util.*; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.*; import java.util.logging.*; -import java.util.regex.*; -import java.util.stream.*; +import java.util.regex.Pattern; +import java.util.stream.Stream; import org.redkale.net.*; import org.redkale.net.Filter; import org.redkale.net.http.Rest.RestDynSourceType; -import org.redkale.service.*; +import org.redkale.service.Service; import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.*; diff --git a/src/main/java/org/redkale/net/http/HttpServer.java b/src/main/java/org/redkale/net/http/HttpServer.java index c7502805b..4e1a205a2 100644 --- a/src/main/java/org/redkale/net/http/HttpServer.java +++ b/src/main/java/org/redkale/net/http/HttpServer.java @@ -5,24 +5,24 @@ */ package org.redkale.net.http; -import java.lang.reflect.*; -import java.net.*; +import java.lang.reflect.Field; +import java.net.HttpCookie; import java.text.*; -import java.time.*; +import java.time.ZoneId; import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.concurrent.locks.*; -import java.util.function.*; -import java.util.logging.*; -import org.redkale.boot.*; +import java.util.concurrent.atomic.LongAdder; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; +import java.util.logging.Level; +import org.redkale.boot.Application; import org.redkale.mq.*; -import org.redkale.net.*; +import org.redkale.net.Server; import org.redkale.net.http.HttpContext.HttpContextConfig; import org.redkale.net.http.HttpResponse.HttpResponseConfig; -import org.redkale.net.sncp.*; -import org.redkale.service.*; +import org.redkale.net.sncp.Sncp; +import org.redkale.service.Service; import org.redkale.util.*; /** @@ -43,6 +43,8 @@ public class HttpServer extends Server APP_EXECUTOR资源为null @@ -95,6 +97,11 @@ public class HttpServer extends Server getHttpServlets() { return this.dispatcher.getServlets(); } @@ -241,7 +248,13 @@ public class HttpServer extends Server T addRestWebSocketServlet(final ClassLoader classLoader, final Class webSocketType, MessageAgent messageAgent, final String prefix, final AnyValue conf) { + public T addRestWebSocketServlet( + final ClassLoader classLoader, + final Class webSocketType, + final MessageAgent messageAgent, + final String prefix, + final AnyValue conf) { + T servlet = Rest.createRestWebSocketServlet(classLoader, webSocketType, messageAgent); if (servlet != null) { this.dispatcher.addServlet(servlet, prefix, conf); @@ -262,7 +275,13 @@ public class HttpServer extends Server T addRestServlet(final ClassLoader classLoader, final S service, final Class userType, final Class baseServletType, final String prefix) { + public T addRestServlet( + final ClassLoader classLoader, + final S service, + final Class userType, + final Class baseServletType, + final String prefix) { + return addRestServlet(classLoader, null, service, userType, baseServletType, prefix); } @@ -281,72 +300,72 @@ public class HttpServer extends Server T addRestServlet(final ClassLoader classLoader, final String name, final S service, final Class userType, final Class baseServletType, final String prefix) { + public T addRestServlet( + final ClassLoader classLoader, + final String name, + final S service, + final Class userType, + final Class baseServletType, + final String prefix) { + T servlet = null; - final boolean sncp = Sncp.isSncpDyn(service); - final String resname = name == null ? (sncp ? Sncp.getResourceName(service) : "") : name; - final Class serviceType = Sncp.getResourceType(service); - if (name != null) { - for (final HttpServlet item : ((HttpDispatcherServlet) this.dispatcher).getServlets()) { - if (!(item instanceof HttpServlet)) { - continue; + addLock.lock(); + try { + final boolean sncp = Sncp.isSncpDyn(service); + final String resname = name == null ? (sncp ? Sncp.getResourceName(service) : "") : name; + final Class serviceType = Sncp.getResourceType(service); + + for (final HttpServlet item : this.dispatcher.getServlets()) { + Rest.RestDynSourceType dst = item.getClass().getAnnotation(Rest.RestDynSourceType.class); + if (dst != null && serviceType.equals(dst.value())) { + servlet = (T) item; + break; } - if (item.getClass().getAnnotation(Rest.RestDyn.class) == null) { - continue; - } - try { - Field field = item.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME); - if (serviceType.equals(field.getType())) { - servlet = (T) item; - break; + } + final boolean first = servlet == null; + if (servlet == null) { + servlet = Rest.createRestServlet(classLoader, userType, baseServletType, serviceType); + if (servlet != null) { + servlet._reqtopic = MessageAgent.generateHttpReqTopic(Rest.getRestModule(service)); + if (serviceType.getAnnotation(MessageMultiConsumer.class) != null) { + MessageMultiConsumer mmc = serviceType.getAnnotation(MessageMultiConsumer.class); + servlet._mmctopic = MessageAgent.generateHttpReqTopic(mmc.module(), resname); } - } catch (NoSuchFieldException | SecurityException e) { - logger.log(Level.SEVERE, "serviceType = " + serviceType + ", servletClass = " + item.getClass(), e); } } - } - final boolean first = servlet == null; - if (servlet == null) { - servlet = Rest.createRestServlet(classLoader, userType, baseServletType, serviceType); - if (servlet != null) { - servlet._reqtopic = MessageAgent.generateHttpReqTopic(Rest.getRestModule(service)); - if (serviceType.getAnnotation(MessageMultiConsumer.class) != null) { - MessageMultiConsumer mmc = serviceType.getAnnotation(MessageMultiConsumer.class); - servlet._mmctopic = MessageAgent.generateHttpReqTopic(mmc.module(), resname); - } + if (servlet == null) { + return null; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null } - } - if (servlet == null) { - return null; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null - } - try { //若提供动态变更Service服务功能,则改Rest服务无法做出相应更新 - Field field = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME); - field.setAccessible(true); + try { //若提供动态变更Service服务功能,则改Rest服务无法做出相应更新 + Field oneField = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME); + oneField.setAccessible(true); - Field mapfield = servlet.getClass().getDeclaredField(Rest.REST_SERVICEMAP_FIELD_NAME); - mapfield.setAccessible(true); + Field mapField = servlet.getClass().getDeclaredField(Rest.REST_SERVICEMAP_FIELD_NAME); + mapField.setAccessible(true); - Service firstService = (Service) field.get(servlet); - if (resname.isEmpty()) { - field.set(servlet, service); - firstService = service; - } - Map map = (Map) mapfield.get(servlet); - if (map == null && !resname.isEmpty()) { - map = new HashMap(); - } - if (map != null) { - map.put(resname, service); - if (firstService != null) { - map.put("", firstService); + Service oneService = (Service) oneField.get(servlet); + if (resname.isEmpty() || oneService == null) { + oneField.set(servlet, service); } + Map map = (Map) mapField.get(servlet); + if (!resname.isEmpty() || oneService != null || map != null) { + if (map == null) { + map = new HashMap(); + } + map.put(resname, service); + if (oneService != null) { + map.put(Sncp.getResourceName(oneService), oneService); + } + mapField.set(servlet, map); + } + } catch (Exception e) { + throw new HttpException(serviceType + " generate rest servlet error", e); } - mapfield.set(servlet, map); - } catch (Exception e) { - throw new HttpException(serviceType + " generate rest servlet error", e); - } - if (first) { - this.dispatcher.addServlet(servlet, prefix, sncp ? Sncp.getResourceConf(service) : null); + if (first) { + this.dispatcher.addServlet(servlet, prefix, sncp ? Sncp.getResourceConf(service) : null); + } + } finally { + addLock.unlock(); } return servlet; } diff --git a/src/main/java/org/redkale/net/http/Rest.java b/src/main/java/org/redkale/net/http/Rest.java index 70dc4207f..277d34635 100644 --- a/src/main/java/org/redkale/net/http/Rest.java +++ b/src/main/java/org/redkale/net/http/Rest.java @@ -10,10 +10,10 @@ import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; import java.lang.reflect.*; -import java.net.*; -import java.nio.channels.*; +import java.net.InetSocketAddress; +import java.nio.channels.CompletionHandler; import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.CompletionStage; import org.redkale.annotation.Comment; import org.redkale.annotation.*; import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; @@ -24,9 +24,9 @@ import org.redkale.convert.*; import org.redkale.convert.json.*; import org.redkale.mq.*; import org.redkale.net.*; -import org.redkale.net.sncp.*; +import org.redkale.net.sncp.Sncp; import org.redkale.service.*; -import org.redkale.source.*; +import org.redkale.source.Flipper; import org.redkale.util.*; /** @@ -300,6 +300,19 @@ public final class Rest { } } + public static void setServiceMap(HttpServlet servlet, Map map) { + if (servlet == null) { + return; + } + try { + Field ts = servlet.getClass().getDeclaredField(REST_SERVICEMAP_FIELD_NAME); + ts.setAccessible(true); + ts.set(servlet, map); + } catch (Exception e) { + throw new RestException(e); + } + } + public static String getRestModule(Service service) { final RestService controller = service.getClass().getAnnotation(RestService.class); if (controller != null && !controller.name().isEmpty()) { @@ -1504,6 +1517,56 @@ public final class Rest { Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME); tostringfield.setAccessible(true); + { //注入 @WebServlet 注解 + String urlpath = ""; + final String defmodulename = getWebModuleNameLowerCase(serviceType); + final int moduleid = controller == null ? 0 : controller.moduleid(); + boolean repair = controller == null ? true : controller.repair(); + final String catalog = controller == null ? "" : controller.catalog(); + + boolean pound = false; + for (MappingEntry entry : entrys) { + if (entry.existsPound) { + pound = true; + break; + } + } + if (defmodulename.isEmpty() || (!pound && entrys.size() <= 2)) { + Set startWiths = new HashSet<>(); + for (MappingEntry entry : entrys) { + String suburl = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) + entry.name; + if ("//".equals(suburl)) { + suburl = "/"; + } else if (suburl.length() > 2 && suburl.endsWith("/")) { + startWiths.add(suburl); + suburl += "*"; + } else { + boolean match = false; + for (String s : startWiths) { + if (suburl.startsWith(s)) { + match = true; + break; + } + } + if (match) { + continue; + } + } + urlpath += "," + suburl; + } + if (urlpath.length() > 0) { + urlpath = urlpath.substring(1); + } + } else { + urlpath = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + defmodulename + "/*"; + } + + classMap.put("type", serviceType.getName()); + classMap.put("url", urlpath); + classMap.put("moduleid", moduleid); + classMap.put("repair", repair); + //classMap.put("comment", comment); //不显示太多信息 + } java.util.function.Supplier sSupplier = () -> JsonConvert.root().convertTo(classMap); tostringfield.set(obj, sSupplier); @@ -1779,6 +1842,9 @@ public final class Rest { if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) { restConverts.add(new Object[]{rcs, rcc}); } + if (dynsimple && entry.rpconly) { //需要读取http header + dynsimple = false; + } mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, entry.newMethodName, "(" + reqDesc + respDesc + ")V", null, new String[]{"java/io/IOException"})); //mv.setDebug(true); diff --git a/src/main/java/org/redkale/net/http/WebSocketNode.java b/src/main/java/org/redkale/net/http/WebSocketNode.java index 27a63c42c..fbc666ba6 100644 --- a/src/main/java/org/redkale/net/http/WebSocketNode.java +++ b/src/main/java/org/redkale/net/http/WebSocketNode.java @@ -30,7 +30,7 @@ import org.redkale.util.*; * * @author zhangjx */ -public abstract class WebSocketNode { +public abstract class WebSocketNode implements Service { @Comment("存储用户ID的key前缀") public static final String WS_SOURCE_KEY_USERID_PREFIX = "sncpws_uid:"; @@ -70,13 +70,18 @@ public abstract class WebSocketNode { private int tryAcquireSeconds = 12; + @Override public void init(AnyValue conf) { this.tryAcquireSeconds = Integer.getInteger("redkale.http.websocket.tryAcquireSeconds", 12); if (localEngine != null) { int wsthreads = localEngine.wsThreads; - if (wsthreads == 0) wsthreads = Utility.cpus() * 8; - if (wsthreads > 0) this.semaphore = new Semaphore(wsthreads); + if (wsthreads == 0) { + wsthreads = Utility.cpus() * 8; + } + if (wsthreads > 0) { + this.semaphore = new Semaphore(wsthreads); + } } String mqtopic = this.messageAgent == null ? null : this.messageAgent.generateSncpReqTopic((Service) this); if (mqtopic != null || this.localSncpAddress != null) { @@ -90,6 +95,7 @@ public abstract class WebSocketNode { } } + @Override public void destroy(AnyValue conf) { } @@ -105,7 +111,9 @@ public abstract class WebSocketNode { @Local protected void postDestroy(AnyValue conf) { - if (this.localEngine == null) return; + if (this.localEngine == null) { + return; + } //关掉所有本地本地WebSocket this.localEngine.getLocalWebSockets().forEach(g -> g.close()); if (source != null && wsNodeAddress != null) { @@ -137,17 +145,23 @@ public abstract class WebSocketNode { //-------------------------------------------------------------------------------- final CompletableFuture connect(final Serializable userid) { - if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket connect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + if (logger.isLoggable(Level.FINEST)) { + logger.finest(wsNodeAddress + " receive websocket connect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + } return connect(userid, wsNodeAddress); } final CompletableFuture disconnect(final Serializable userid) { - if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket disconnect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + if (logger.isLoggable(Level.FINEST)) { + logger.finest(wsNodeAddress + " receive websocket disconnect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + } return disconnect(userid, wsNodeAddress); } final CompletableFuture changeUserid(Serializable olduserid, final Serializable newuserid) { - if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket changeUserid event (from " + olduserid + " to " + newuserid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + if (logger.isLoggable(Level.FINEST)) { + logger.finest(wsNodeAddress + " receive websocket changeUserid event (from " + olduserid + " to " + newuserid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + } return changeUserid(olduserid, newuserid, wsNodeAddress); } @@ -167,7 +181,9 @@ public abstract class WebSocketNode { * @return 客户端地址列表 */ protected CompletableFuture> remoteWebSocketAddresses(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Serializable userid) { - if (remoteNode == null) return CompletableFuture.completedFuture(null); + if (remoteNode == null) { + return CompletableFuture.completedFuture(null); + } try { return remoteNode.getWebSocketAddresses(topic, targetAddress, userid); } catch (Exception e) { @@ -188,7 +204,9 @@ public abstract class WebSocketNode { if (this.source != null) { tryAcquireSemaphore(); CompletableFuture> result = this.source.smembersAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) result.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + result.whenComplete((r, e) -> releaseSemaphore()); + } return result; } Set rs = new LinkedHashSet<>(); @@ -208,8 +226,12 @@ public abstract class WebSocketNode { public CompletableFuture>> getRpcNodeWebSocketAddresses(final Serializable userid) { CompletableFuture> sncpFuture = getRpcNodeAddresses(userid); return sncpFuture.thenCompose((Collection addrs) -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(new HashMap<>()); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket found userid:" + userid + " on " + addrs); + } + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(new HashMap<>()); + } CompletableFuture>> future = null; for (final WebSocketAddress nodeAddress : addrs) { CompletableFuture>> mapFuture = getWebSocketAddresses(nodeAddress.getTopic(), nodeAddress.getAddr(), userid) @@ -244,13 +266,21 @@ public abstract class WebSocketNode { CompletableFuture localFuture = this.localEngine == null ? null : CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); tryAcquireSemaphore(); CompletableFuture> addrsFuture = source.smembersAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } CompletableFuture remoteFuture = addrsFuture.thenCompose(addrs -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket getUserSize on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket getUserSize on " + addrs); + } + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(0); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.getUserSize(addr.getTopic(), addr.getAddr()) : future.thenCombine(remoteNode.getUserSize(addr.getTopic(), addr.getAddr()), (a, b) -> a + b); } @@ -272,7 +302,9 @@ public abstract class WebSocketNode { tryAcquireSemaphore(); CompletableFuture> listFuture = this.source.keysStartsWithAsync(WS_SOURCE_KEY_USERID_PREFIX); CompletableFuture> rs = listFuture.thenApply(v -> new LinkedHashSet<>(v.stream().map(x -> x.substring(WS_SOURCE_KEY_USERID_PREFIX.length())).collect(Collectors.toList()))); - if (semaphore != null) rs.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + rs.whenComplete((r, e) -> releaseSemaphore()); + } return rs; } @@ -285,24 +317,36 @@ public abstract class WebSocketNode { */ @Local public CompletableFuture existsWebSocket(final Serializable userid) { - if (userid instanceof WebSocketUserAddress) return existsWebSocket((WebSocketUserAddress) userid); + if (userid instanceof WebSocketUserAddress) { + return existsWebSocket((WebSocketUserAddress) userid); + } CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); + if (this.localEngine != null) { + localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); + } if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + } //没有CacheSource就不会有分布式节点 return localFuture == null ? CompletableFuture.completedFuture(false) : localFuture; } //远程节点关闭 tryAcquireSemaphore(); CompletableFuture> addrsFuture = source.smembersAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } CompletableFuture remoteFuture = addrsFuture.thenCompose(addrs -> { //if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false); + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(false); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.existsWebSocket(userid, addr.getTopic(), addr.getAddr()) : future.thenCombine(remoteNode.existsWebSocket(userid, addr.getTopic(), addr.getAddr()), (a, b) -> a | b); } @@ -320,22 +364,34 @@ public abstract class WebSocketNode { */ @Local public CompletableFuture existsWebSocket(final WebSocketUserAddress userAddress) { - if (this.localEngine != null && localEngine.existsLocalWebSocket(userAddress.userid())) return CompletableFuture.completedFuture(true); + if (this.localEngine != null && localEngine.existsLocalWebSocket(userAddress.userid())) { + return CompletableFuture.completedFuture(true); + } if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + } //没有CacheSource就不会有分布式节点 return CompletableFuture.completedFuture(false); } Collection addrs = userAddress.addresses(); - if (addrs != null) addrs = new ArrayList<>(addrs); //不能修改参数内部值 + if (addrs != null) { + addrs = new ArrayList<>(addrs); //不能修改参数内部值 + } if (userAddress.address() != null) { - if (addrs == null) addrs = new ArrayList<>(); + if (addrs == null) { + addrs = new ArrayList<>(); + } addrs.add(userAddress.address()); } - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false); + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(false); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.existsWebSocket(userAddress.userid(), addr.getTopic(), addr.getAddr()) : future.thenCombine(remoteNode.existsWebSocket(userAddress.userid(), addr.getTopic(), addr.getAddr()), (a, b) -> a | b); } @@ -368,9 +424,13 @@ public abstract class WebSocketNode { private CompletableFuture forceCloseWebSocket(final Serializable userid, final WebSocketUserAddress userAddress) { CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userAddress == null ? userid : userAddress.userid())); + if (this.localEngine != null) { + localFuture = CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userAddress == null ? userid : userAddress.userid())); + } if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + } //没有CacheSource就不会有分布式节点 return localFuture == null ? CompletableFuture.completedFuture(0) : localFuture; } @@ -379,23 +439,37 @@ public abstract class WebSocketNode { if (userAddress == null) { tryAcquireSemaphore(); addrsFuture = (CompletableFuture) source.smembersAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } } else { Collection addrs = userAddress.addresses(); - if (addrs != null) addrs = new ArrayList<>(addrs); //不能修改参数内部值 + if (addrs != null) { + addrs = new ArrayList<>(addrs); //不能修改参数内部值 + } if (userAddress.address() != null) { - if (addrs == null) addrs = new ArrayList<>(); + if (addrs == null) { + addrs = new ArrayList<>(); + } addrs.add(userAddress.address()); } - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(0); + } addrsFuture = CompletableFuture.completedFuture(addrs); } CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket found userid:" + userid + " on " + addrs); + } + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(0); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.forceCloseWebSocket(userid, addr.getTopic(), addr.getAddr()) : future.thenCombine(remoteNode.forceCloseWebSocket(userid, addr.getTopic(), addr.getAddr()), (a, b) -> a + b); } @@ -538,7 +612,9 @@ public abstract class WebSocketNode { */ @Local public CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final Serializable... userids) { - if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + if (userids == null || userids.length < 1) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } if (userids[0] instanceof WebSocketUserAddress) { WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length]; for (int i = 0; i < useraddrs.length; i++) { @@ -546,7 +622,9 @@ public abstract class WebSocketNode { } return sendMessage(convert, message0, last, useraddrs); } - if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, userids)); + if (message0 instanceof CompletableFuture) { + return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, userids)); + } final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(WebSocketPacket.FrameType.TEXT, ((TextConvert) convert).convertToBytes(message0), last) : new WebSocketPacket(WebSocketPacket.FrameType.BINARY, ((BinaryConvert) convert).convertToBytes(message0), last)); if (this.localEngine != null && this.source == null) { //本地模式且没有分布式 return this.localEngine.sendLocalMessage(message, last, userids); @@ -564,10 +642,14 @@ public abstract class WebSocketNode { } tryAcquireSemaphore(); CompletableFuture>> addrsFuture = source.smembersAsync(WebSocketAddress.class, keys); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } rsfuture = addrsFuture.thenCompose(addrs -> { if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); + if (logger.isLoggable(Level.FINER)) { + logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); + } return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); } Map> addrUsers = new HashMap<>(); @@ -604,8 +686,12 @@ public abstract class WebSocketNode { */ @Local public CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final WebSocketUserAddress... useraddrs) { - if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, useraddrs)); + if (useraddrs == null || useraddrs.length < 1) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + if (message0 instanceof CompletableFuture) { + return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, useraddrs)); + } final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last)); if (this.localEngine != null && this.source == null) { //本地模式且没有分布式 return this.localEngine.sendLocalMessage(message, last, userAddressToUserids(useraddrs)); @@ -627,14 +713,20 @@ public abstract class WebSocketNode { } protected CompletableFuture sendOneUserMessage(final Object message, final boolean last, final Serializable userid) { - if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid)); + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid)); + } if (logger.isLoggable(Level.FINEST)) { logger.finest("websocket want send message {userid:" + userid + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); } CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = localEngine.sendLocalMessage(message, last, userid); + if (this.localEngine != null) { + localFuture = localEngine.sendLocalMessage(message, last, userid); + } if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + } //没有CacheSource就不会有分布式节点 return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture; } @@ -642,16 +734,24 @@ public abstract class WebSocketNode { final Object remoteMessage = formatRemoteMessage(message); tryAcquireSemaphore(); CompletableFuture> addrsFuture = source.smembersAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } CompletableFuture remoteFuture = addrsFuture.thenCompose(addrs -> { if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node "); + if (logger.isLoggable(Level.FINER)) { + logger.finer("websocket not found userid:" + userid + " on any node "); + } return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); } - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + wsNodeAddress + ") found userid:" + userid + " on " + addrs); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket(localaddr=" + wsNodeAddress + ") found userid:" + userid + " on " + addrs); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userid) : future.thenCombine(remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userid), (a, b) -> a | b); } @@ -661,7 +761,9 @@ public abstract class WebSocketNode { } protected CompletableFuture sendOneAddrMessage(final WebSocketAddress addr, final Object message, final boolean last, final Serializable... userids) { - if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(addr, msg, last, userids)); + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(addr, msg, last, userids)); + } if (logger.isLoggable(Level.FINEST) && this.localEngine == null) { //只打印远程模式的 logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + addr + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); } @@ -669,7 +771,9 @@ public abstract class WebSocketNode { return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids); } if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + } //没有CacheSource就不会有分布式节点 return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); } @@ -678,7 +782,9 @@ public abstract class WebSocketNode { } protected Serializable[] userAddressToUserids(WebSocketUserAddress... useraddrs) { - if (useraddrs == null || useraddrs.length == 1) return new Serializable[0]; + if (useraddrs == null || useraddrs.length == 1) { + return new Serializable[0]; + } Set set = new HashSet<>(); for (WebSocketUserAddress userAddress : useraddrs) { set.add(userAddress.userid()); @@ -808,7 +914,9 @@ public abstract class WebSocketNode { */ @Local public CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message0, final boolean last) { - if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> broadcastMessage(wsrange, convert, msg, last)); + if (message0 instanceof CompletableFuture) { + return ((CompletableFuture) message0).thenApply(msg -> broadcastMessage(wsrange, convert, msg, last)); + } final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last)); if (this.localEngine != null && this.source == null) { //本地模式且没有分布式 return this.localEngine.broadcastLocalMessage(wsrange, message, last); @@ -817,13 +925,21 @@ public abstract class WebSocketNode { CompletableFuture localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalMessage(wsrange, message, last); tryAcquireSemaphore(); CompletableFuture> addrsFuture = source.smembersAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } CompletableFuture remoteFuture = addrsFuture.thenCompose(addrs -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast message (" + remoteMessage + ") on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket broadcast message (" + remoteMessage + ") on " + addrs); + } + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(0); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.broadcastMessage(addr.getTopic(), addr.getAddr(), wsrange, remoteMessage, last) : future.thenCombine(remoteNode.broadcastMessage(addr.getTopic(), addr.getAddr(), wsrange, remoteMessage, last), (a, b) -> a | b); } @@ -847,13 +963,21 @@ public abstract class WebSocketNode { CompletableFuture localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalAction(action); tryAcquireSemaphore(); CompletableFuture> addrsFuture = source.smembersAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } CompletableFuture remoteFuture = addrsFuture.thenCompose(addrs -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast action (" + action + ") on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket broadcast action (" + action + ") on " + addrs); + } + if (addrs == null || addrs.isEmpty()) { + return CompletableFuture.completedFuture(0); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.broadcastAction(addr.getTopic(), addr.getAddr(), action) : future.thenCombine(remoteNode.broadcastAction(addr.getTopic(), addr.getAddr(), action), (a, b) -> a | b); } @@ -873,7 +997,9 @@ public abstract class WebSocketNode { */ @Local public CompletableFuture sendAction(final WebSocketAction action, final Serializable... userids) { - if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + if (userids == null || userids.length < 1) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } if (userids[0] instanceof WebSocketUserAddress) { WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length]; for (int i = 0; i < useraddrs.length; i++) { @@ -896,10 +1022,14 @@ public abstract class WebSocketNode { } tryAcquireSemaphore(); CompletableFuture>> addrsFuture = source.smembersAsync(WebSocketAddress.class, keys); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } rsfuture = addrsFuture.thenCompose(addrs -> { if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); + if (logger.isLoggable(Level.FINER)) { + logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); + } return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); } Map> addrUsers = new HashMap<>(); @@ -934,7 +1064,9 @@ public abstract class WebSocketNode { */ @Local public CompletableFuture sendAction(final WebSocketAction action, final WebSocketUserAddress... useraddrs) { - if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + if (useraddrs == null || useraddrs.length < 1) { + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } if (this.localEngine != null && this.source == null) { //本地模式且没有分布式 return this.localEngine.sendLocalAction(action, userAddressToUserids(useraddrs)); } @@ -957,25 +1089,37 @@ public abstract class WebSocketNode { logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); } CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = localEngine.sendLocalAction(action, userid); + if (this.localEngine != null) { + localFuture = localEngine.sendLocalAction(action, userid); + } if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + } //没有CacheSource就不会有分布式节点 return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture; } //远程节点发送操作 tryAcquireSemaphore(); CompletableFuture> addrsFuture = source.smembersAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + if (semaphore != null) { + addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } CompletableFuture remoteFuture = addrsFuture.thenCompose(addrs -> { if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node "); + if (logger.isLoggable(Level.FINER)) { + logger.finer("websocket not found userid:" + userid + " on any node "); + } return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); } - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + localSncpAddress + ") found userid:" + userid + " on " + addrs); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket(localaddr=" + localSncpAddress + ") found userid:" + userid + " on " + addrs); + } CompletableFuture future = null; for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; + if (addr == null || addr.equals(wsNodeAddress)) { + continue; + } future = future == null ? remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userid) : future.thenCombine(remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userid), (a, b) -> a | b); } @@ -992,7 +1136,9 @@ public abstract class WebSocketNode { return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalAction(action, userids); } if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + } //没有CacheSource就不会有分布式节点 return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); } @@ -1000,16 +1146,28 @@ public abstract class WebSocketNode { } protected Object formatRemoteMessage(Object message) { - if (message instanceof WebSocketPacket) return message; - if (message instanceof byte[]) return message; - if (message instanceof CharSequence) return message; - if (sendConvert instanceof TextConvert) ((TextConvert) sendConvert).convertTo(message); - if (sendConvert instanceof BinaryConvert) ((BinaryConvert) sendConvert).convertTo(message); + if (message instanceof WebSocketPacket) { + return message; + } + if (message instanceof byte[]) { + return message; + } + if (message instanceof CharSequence) { + return message; + } + if (sendConvert instanceof TextConvert) { + ((TextConvert) sendConvert).convertTo(message); + } + if (sendConvert instanceof BinaryConvert) { + ((BinaryConvert) sendConvert).convertTo(message); + } return JsonConvert.root().convertTo(message); } protected boolean tryAcquireSemaphore() { - if (this.semaphore == null) return true; + if (this.semaphore == null) { + return true; + } try { return this.semaphore.tryAcquire(tryAcquireSeconds, TimeUnit.SECONDS); } catch (Exception e) { @@ -1018,6 +1176,8 @@ public abstract class WebSocketNode { } protected void releaseSemaphore() { - if (this.semaphore != null) this.semaphore.release(); + if (this.semaphore != null) { + this.semaphore.release(); + } } } diff --git a/src/main/java/org/redkale/net/sncp/OldSncpClient.java b/src/main/java/org/redkale/net/sncp/OldSncpClient.java index 4362dc039..023360982 100644 --- a/src/main/java/org/redkale/net/sncp/OldSncpClient.java +++ b/src/main/java/org/redkale/net/sncp/OldSncpClient.java @@ -19,7 +19,7 @@ import org.redkale.mq.*; import org.redkale.net.*; import org.redkale.net.sncp.Sncp.SncpDyn; import static org.redkale.net.sncp.SncpHeader.HEADER_SIZE; -import org.redkale.net.sncp.SncpServiceInfo.SncpServiceAction; +import org.redkale.net.sncp.SncpRemoteInfo.SncpRemoteAction; import org.redkale.service.*; import org.redkale.source.*; import org.redkale.util.*; @@ -31,6 +31,7 @@ import org.redkale.util.*; * * @author zhangjx */ +@Deprecated(since = "2.8.0") public final class OldSncpClient { protected static final Logger logger = Logger.getLogger(OldSncpClient.class.getSimpleName()); @@ -53,7 +54,7 @@ public final class OldSncpClient { protected final int serviceVersion; - protected final SncpServiceAction[] actions; + protected final SncpRemoteAction[] actions; protected final MessageAgent messageAgent; @@ -82,12 +83,12 @@ public final class OldSncpClient { this.name = serviceResourceName; Class serviceResourceType = ResourceFactory.getResourceType(serviceTypeOrImplClass); //serviceResourceType this.serviceid = Sncp.serviceid(serviceResourceName, serviceResourceType); - final List methodens = new ArrayList<>(); + final List methodens = new ArrayList<>(); //------------------------------------------------------------------------------ for (Map.Entry en : Sncp.loadMethodActions(serviceResourceType).entrySet()) { - methodens.add(new SncpServiceAction(serviceClass, en.getValue(), serviceid, en.getKey())); + methodens.add(new SncpRemoteAction(serviceClass, en.getValue(), serviceid, en.getKey())); } - this.actions = methodens.toArray(new SncpServiceAction[methodens.size()]); + this.actions = methodens.toArray(new SncpRemoteAction[methodens.size()]); this.addrBytes = clientSncpAddress == null ? new byte[4] : clientSncpAddress.getAddress().getAddress(); this.addrPort = clientSncpAddress == null ? 0 : clientSncpAddress.getPort(); if (this.addrBytes.length != 4) { @@ -160,7 +161,7 @@ public final class OldSncpClient { //只给远程模式调用的 public T remote(final int index, final Object... params) { - final SncpServiceAction action = actions[index]; + final SncpRemoteAction action = actions[index]; final CompletionHandler handlerFunc = action.paramHandlerIndex >= 0 ? (CompletionHandler) params[action.paramHandlerIndex] : null; if (action.paramHandlerIndex >= 0) { params[action.paramHandlerIndex] = null; @@ -206,7 +207,7 @@ public final class OldSncpClient { } } - private CompletableFuture remote0(final CompletionHandler handler, final Transport transport, final SocketAddress addr0, final SncpServiceAction action, final Object... params) { + private CompletableFuture remote0(final CompletionHandler handler, final Transport transport, final SocketAddress addr0, final SncpRemoteAction action, final Object... params) { final String traceid = Traces.currTraceid(); final Type[] myparamtypes = action.paramTypes; final Class[] myparamclass = action.paramClasses; @@ -404,7 +405,7 @@ public final class OldSncpClient { }); } - private void checkResult(long seqid, final SncpServiceAction action, ByteBuffer buffer) { + private void checkResult(long seqid, final SncpRemoteAction action, ByteBuffer buffer) { long rseqid = buffer.getLong(); if (rseqid != seqid) { throw new SncpException("sncp(" + action.method + ") response.seqid = " + seqid + ", but request.seqid =" + rseqid); @@ -429,7 +430,7 @@ public final class OldSncpClient { buffer.getChar(); //端口 } - private void fillHeader(ByteArray buffer, SncpServiceAction action, long seqid, String traceid, int bodyLength) { + private void fillHeader(ByteArray buffer, SncpRemoteAction action, long seqid, String traceid, int bodyLength) { action.header.writeTo(buffer, addrBytes, addrPort, seqid, bodyLength, 0); //结果码, 请求方固定传0 } diff --git a/src/main/java/org/redkale/net/sncp/Sncp.java b/src/main/java/org/redkale/net/sncp/Sncp.java index bcf9ef299..dcbf82833 100644 --- a/src/main/java/org/redkale/net/sncp/Sncp.java +++ b/src/main/java/org/redkale/net/sncp/Sncp.java @@ -10,8 +10,7 @@ import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; import java.lang.reflect.*; -import java.net.*; -import java.nio.channels.*; +import java.nio.channels.CompletionHandler; import java.util.*; import org.redkale.annotation.*; import org.redkale.annotation.ResourceType; @@ -19,11 +18,10 @@ 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.*; -import org.redkale.mq.*; -import org.redkale.net.*; -import org.redkale.net.http.*; -import org.redkale.net.sncp.SncpServiceInfo.SncpServiceAction; +import org.redkale.convert.Convert; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.mq.MessageAgent; +import org.redkale.net.sncp.SncpRemoteInfo.SncpRemoteAction; import org.redkale.service.*; import org.redkale.util.*; @@ -150,9 +148,18 @@ public abstract class Sncp { return rs; } - public static SncpServiceInfo createSncpServiceInfo(String resourceName, - Class resourceServiceType, Class serviceImplClass, Convert convert, SncpClient sncpClient, MessageAgent messageAgent, SncpMessageClient messageClient) { - return new SncpServiceInfo(resourceName, resourceServiceType, serviceImplClass, convert, sncpClient, messageAgent, messageClient); + public static SncpRemoteInfo createSncpRemoteInfo(String resourceName, + Class resourceServiceType, Class serviceImplClass, Convert convert, SncpRpcGroups sncpRpcGroups, + SncpClient sncpClient, MessageAgent messageAgent, String remoteGroup) { + return new SncpRemoteInfo(resourceName, resourceServiceType, serviceImplClass, convert, sncpRpcGroups, sncpClient, messageAgent, remoteGroup); + } + + public static String resourceid(String resourceName, Class resourceType) { + return resourceType.getName() + ':' + (resourceName == null ? "" : resourceName); + } + + public static Uint128 serviceid(String serviceResourceName, Class serviceResourceType) { + return hash(resourceid(serviceResourceName, serviceResourceType)); } public static Uint128 actionid(final RpcAction action) { @@ -183,10 +190,6 @@ public abstract class Sncp { return hash(sb.toString()); } - public static Uint128 serviceid(String serviceResourceName, Class serviceResourceType) { - return hash(serviceResourceType.getName() + ':' + serviceResourceName); - } - /** * 对类名或者name字符串进行hash。 * @@ -215,7 +218,7 @@ public abstract class Sncp { } public static int getVersion(Service service) { - return -1; //暂不实现Version + return -1; //预留功能,暂不实现 } public static String getResourceName(Service service) { @@ -250,66 +253,6 @@ public abstract class Sncp { } } - 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 (OldSncpClient) ts.get(service); - } catch (Exception e) { - throw new SncpException(service + " not found " + FIELDPREFIX + "_client"); - } - } - - public static MessageAgent getMessageAgent(Service service) { - if (service == null || !isSncpDyn(service)) { - return null; - } - try { - Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_messageAgent"); - ts.setAccessible(true); - return (MessageAgent) ts.get(service); - } catch (Exception e) { - throw new SncpException(service + " not found " + FIELDPREFIX + "_messageAgent"); - } - } - - public static void setMessageAgent(Service service, MessageAgent messageAgent) { - if (service == null || !isSncpDyn(service)) { - return; - } - try { - Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_messageAgent"); - ts.setAccessible(true); - ts.set(service, messageAgent); - if (service instanceof WebSocketNode) { - Field c = WebSocketNode.class.getDeclaredField("messageAgent"); - c.setAccessible(true); - c.set(service, messageAgent); - } - } catch (Exception e) { - throw new SncpException(service + " not found " + FIELDPREFIX + "_messageAgent"); - } - } - - public static boolean updateTransport(Service service, - final TransportFactory transportFactory, String name, String protocol, InetSocketAddress clientAddress, - final Set groups, final Collection addresses) { - if (!isSncpDyn(service)) { - return false; - } - OldSncpClient client = getSncpOldClient(service); - client.setRemoteGroups(groups); - if (client.getRemoteGroupTransport() != null) { - client.getRemoteGroupTransport().updateRemoteAddresses(addresses); - } else { - client.setRemoteGroupTransport(transportFactory.createTransport(name, protocol, clientAddress, addresses)); - } - return true; - } - static void checkAsyncModifier(Class param, Method method) { if (param == CompletionHandler.class) { return; @@ -418,7 +361,7 @@ public abstract class Sncp { /** *

-     * public class TestService implements Service{
+     * public class TestService implements Service {
      *
      *      public String findSomeThing(){
      *          return "hello";
@@ -440,16 +383,10 @@ public abstract class Sncp {
      * @Resource(name = "")
      * @SncpDyn(remote = false)
      * @ResourceType(TestService.class)
-     * public final class _DynLocalTestService extends TestService{
+     * public final class _DynLocalTestService extends TestService {
      *
-     * private AnyValue _redkale_conf;
+     *      private AnyValue _redkale_conf;
      *
-     * private OldSncpClient _redkale_client;
-     *
-     * @Override
-     *      public String toString() {
-     *          return _redkale_selfstring == null ? super.toString() : _redkale_selfstring;
-     *      }
      * }
      * 
* @@ -477,11 +414,7 @@ public abstract class Sncp { throw new SncpException(serviceImplClass + " is abstract"); } final String supDynName = serviceImplClass.getName().replace('.', '/'); - final String clientName = OldSncpClient.class.getName().replace('.', '/'); - final String sncpInfoName = SncpServiceInfo.class.getName().replace('.', '/'); final String resDesc = Type.getDescriptor(Resource.class); - final String sncpInfoDesc = Type.getDescriptor(SncpServiceInfo.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; @@ -543,18 +476,6 @@ public abstract class Sncp { fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null); fv.visitEnd(); } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_client", clientDesc, null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncpInfo", sncpInfoDesc, null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_messageAgent", Type.getDescriptor(MessageAgent.class), null, null); - fv.visitEnd(); - } { //构造函数 mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); //mv.setDebug(true); @@ -564,26 +485,6 @@ public abstract class Sncp { mv.visitMaxs(1, 1); mv.visitEnd(); } - { // toString() - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncpInfo", sncpInfoDesc); - Label l1 = new Label(); - mv.visitJumpInsn(IFNONNULL, l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false); - Label l2 = new Label(); - mv.visitJumpInsn(GOTO, l2); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncpInfo", sncpInfoDesc); - mv.visitMethodInsn(INVOKEVIRTUAL, sncpInfoName, "toSimpleString", "()Ljava/lang/String;", false); - mv.visitLabel(l2); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } cw.visitEnd(); byte[] bytes = cw.toByteArray(); Class newClazz = new ClassLoader(loader) { @@ -597,36 +498,29 @@ public abstract class Sncp { try { Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - c = newClazz.getDeclaredField(FIELDPREFIX + "_client"); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - c = newClazz.getDeclaredField(FIELDPREFIX + "_sncpInfo"); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - c = newClazz.getDeclaredField(FIELDPREFIX + "_messageAgent"); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); } catch (Exception e) { } return (Class) newClazz; } - public static T createSimpleLocalService(final Class serviceImplClass, final MessageAgent messageAgent, - final ResourceFactory resourceFactory, final TransportFactory transportFactory, final InetSocketAddress clientSncpAddress, final String... groups) { - return createLocalService(null, "", serviceImplClass, messageAgent, resourceFactory, transportFactory, clientSncpAddress, Utility.ofSet(groups), null); + public static T createSimpleLocalService(Class serviceImplClass, ResourceFactory resourceFactory) { + return createLocalService(null, "", serviceImplClass, resourceFactory, null, null, null, null, null); } /** * * 创建本地模式Service实例 * - * @param Service泛型 - * @param classLoader ClassLoader - * @param name 资源名 - * @param serviceImplClass Service类 - * @param messageAgent MQ管理器 - * @param resourceFactory ResourceFactory - * @param transportFactory TransportFactory - * @param clientSncpAddress 本地IP地址 - * @param groups 所有的组节点,包含自身 - * @param conf 启动配置项 + * @param Service泛型 + * @param classLoader ClassLoader + * @param name 资源名 + * @param serviceImplClass Service类 + * @param resourceFactory ResourceFactory + * @param sncpRpcGroups SncpRpcGroups + * @param client SncpClient + * @param agent MessageAgent + * @param remoteGroup 所有的组节点 + * @param conf 启动配置项 * * @return Service的本地模式实例 */ @@ -635,11 +529,11 @@ public abstract class Sncp { final RedkaleClassLoader classLoader, final String name, final Class serviceImplClass, - final MessageAgent messageAgent, final ResourceFactory resourceFactory, - final TransportFactory transportFactory, - final InetSocketAddress clientSncpAddress, - final Set groups, + final SncpRpcGroups sncpRpcGroups, + final SncpClient client, + final MessageAgent agent, + final String remoteGroup, final AnyValue conf) { try { final Class newClazz = createLocalServiceClass(classLoader, name, serviceImplClass); @@ -663,8 +557,8 @@ public abstract class Sncp { } field.setAccessible(true); RedkaleClassLoader.putReflectionField(loop.getName(), field); - if (remoteService == null && clientSncpAddress != null) { - remoteService = createRemoteService(classLoader, name, serviceImplClass, messageAgent, transportFactory, clientSncpAddress, groups, conf); + if (remoteService == null && sncpRpcGroups != null && client != null) { + remoteService = createRemoteService(classLoader, name, serviceImplClass, resourceFactory, sncpRpcGroups, client, agent, remoteGroup, conf); } if (remoteService != null) { field.set(service, remoteService); @@ -672,37 +566,10 @@ public abstract class Sncp { } } while ((loop = loop.getSuperclass()) != Object.class); } - OldSncpClient client = null; - { - try { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client"); - c.setAccessible(true); - client = new OldSncpClient(name, serviceImplClass, service, messageAgent, transportFactory, false, newClazz, clientSncpAddress); - c.set(service, client); - if (transportFactory != null) { - transportFactory.addSncpService(service); - } - } catch (NoSuchFieldException ne) { - ne.printStackTrace(); - } - } - if (messageAgent != null) { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_messageAgent"); - c.setAccessible(true); - c.set(service, messageAgent); - } - if (client == null) { - return service; - } { Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); c.setAccessible(true); c.set(service, conf); - if (service instanceof WebSocketNode) { - c = WebSocketNode.class.getDeclaredField("messageAgent"); - c.setAccessible(true); - c.set(service, messageAgent); - } } return service; } catch (RuntimeException rex) { @@ -712,9 +579,15 @@ public abstract class Sncp { } } - public static T createSimpleRemoteService(final Class serviceImplClass, final MessageAgent messageAgent, - final TransportFactory transportFactory, final InetSocketAddress clientSncpAddress, final String... groups) { - return createRemoteService(null, "", serviceImplClass, messageAgent, transportFactory, clientSncpAddress, Utility.ofSet(groups), null); + public static T createSimpleRemoteService(Class serviceImplClass, ResourceFactory resourceFactory, + SncpRpcGroups sncpRpcGroups, SncpClient client, String group) { + if (sncpRpcGroups == null) { + throw new SncpException("SncpRpcGroups is null"); + } + if (client == null) { + throw new SncpException("SncpClient is null"); + } + return createRemoteService(null, "", serviceImplClass, resourceFactory, sncpRpcGroups, client, null, group, null); } /** @@ -722,27 +595,27 @@ public abstract class Sncp { * @Resource(name = "") * @SncpDyn(remote = true) * @ResourceType(TestService.class) - * public final class _DynRemoteTestService extends TestService{ + * public final class _DynRemoteTestService extends TestService { * - * private AnyValue _redkale_conf; + * private AnyValue _redkale_conf; * - * private SncpClient _redkale_client; + * private SncpClient _redkale_client; * - * private SncpServiceInfo _redkale_sncpInfo; + * private SncpRemoteInfo _redkale_sncp; * - * @Override + * @Override * public void createSomeThing(TestBean bean){ - * _redkale_client.remote(_redkale_sncpInfo, 0, bean); + * _redkale_client.remote(_redkale_sncp, 0, bean); * } * * @Override * public String findSomeThing(){ - * return _redkale_client.remote(_redkale_sncpInfo, 1); + * return (String)_redkale_client.remote(_redkale_sncp, 1); * } * * @Override * public String updateSomeThing(String id){ - * return _redkale_client.remote(_redkale_sncpInfo, 2, id); + * return (String)_redkale_client.remote(_redkale_sncp, 2, id); * } * } * @@ -753,44 +626,48 @@ public abstract class Sncp { * @param classLoader ClassLoader * @param name 资源名 * @param serviceTypeOrImplClass Service类 - * @param messageAgent MQ管理器 - * @param transportFactory TransportFactory - * @param clientAddress 本地IP地址 - * @param groups0 所有的组节点,包含自身 + * @param resourceFactory ResourceFactory + * @param sncpRpcGroups SncpRpcGroups + * @param client SncpClient + * @param agent MessageAgent + * @param remoteGroup 所有的组节点 * @param conf 启动配置项 * * @return Service的远程模式实例 */ @SuppressWarnings("unchecked") - public static T createRemoteService( final ClassLoader classLoader, final String name, final Class serviceTypeOrImplClass, - final MessageAgent messageAgent, - final TransportFactory transportFactory, - final InetSocketAddress clientAddress, - final Set groups0, + final ResourceFactory resourceFactory, + final SncpRpcGroups sncpRpcGroups, + final SncpClient client, + final MessageAgent agent, + final String remoteGroup, final AnyValue conf) { if (serviceTypeOrImplClass == null) { - return null; + throw new SncpException("Service implement class is null"); } if (!Service.class.isAssignableFrom(serviceTypeOrImplClass)) { - return null; + throw new SncpException(serviceTypeOrImplClass + " is not Service type"); + } + if ((sncpRpcGroups == null || client == null) && agent == null) { + throw new SncpException("SncpRpcGroups/SncpClient and MessageAgent are both null"); } - final Set groups = groups0 == null ? new HashSet<>() : groups0; ResourceFactory.checkResourceName(name); final int mod = serviceTypeOrImplClass.getModifiers(); boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceTypeOrImplClass.isInterface()); if (!java.lang.reflect.Modifier.isPublic(mod)) { return null; } + final SncpRemoteInfo info = createSncpRemoteInfo(name, serviceTypeOrImplClass, serviceTypeOrImplClass, BsonConvert.root(), sncpRpcGroups, client, agent, remoteGroup); final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/'); - final String clientName = OldSncpClient.class.getName().replace('.', '/'); - final String sncpInfoName = SncpServiceInfo.class.getName().replace('.', '/'); + final String clientName = SncpClient.class.getName().replace('.', '/'); + final String sncpInfoName = SncpRemoteInfo.class.getName().replace('.', '/'); final String resDesc = Type.getDescriptor(Resource.class); - final String sncpInfoDesc = Type.getDescriptor(SncpServiceInfo.class); - final String clientDesc = Type.getDescriptor(OldSncpClient.class); + final String sncpInfoDesc = Type.getDescriptor(SncpRemoteInfo.class); + final String clientDesc = Type.getDescriptor(SncpClient.class); final String sncpDynDesc = Type.getDescriptor(SncpDyn.class); final String anyValueDesc = Type.getDescriptor(AnyValue.class); final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; @@ -800,33 +677,15 @@ 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(); - 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)); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client"); - c.setAccessible(true); - c.set(service, client); - } - if (messageAgent != null) { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_messageAgent"); - c.setAccessible(true); - c.set(service, messageAgent); - if (service instanceof WebSocketNode) { - c = WebSocketNode.class.getDeclaredField("messageAgent"); - c.setAccessible(true); - c.set(service, messageAgent); - } - } { Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); c.setAccessible(true); c.set(service, conf); } - if (transportFactory != null) { - transportFactory.addSncpService(service); + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncp"); + c.setAccessible(true); + c.set(service, info); } return service; } catch (Throwable ex) { @@ -869,15 +728,7 @@ public abstract class Sncp { fv.visitEnd(); } { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_client", clientDesc, null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncpInfo", sncpInfoDesc, null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_messageAgent", Type.getDescriptor(MessageAgent.class), null, null); + fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncp", sncpInfoDesc, null, null); fv.visitEnd(); } { //构造函数 @@ -901,34 +752,34 @@ public abstract class Sncp { mv.visitMaxs(0, 2); mv.visitEnd(); } - { // toString() - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncpInfo", sncpInfoDesc); - Label l1 = new Label(); - mv.visitJumpInsn(IFNONNULL, l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false); - Label l2 = new Label(); - mv.visitJumpInsn(GOTO, l2); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncpInfo", sncpInfoDesc); - mv.visitMethodInsn(INVOKEVIRTUAL, sncpInfoName, "toSimpleString", "()Ljava/lang/String;", false); - mv.visitLabel(l2); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } +// { // toString() +// mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); +// mv.visitVarInsn(ALOAD, 0); +// mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); +// Label l1 = new Label(); +// mv.visitJumpInsn(IFNONNULL, l1); +// mv.visitVarInsn(ALOAD, 0); +// mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); +// mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false); +// Label l2 = new Label(); +// mv.visitJumpInsn(GOTO, l2); +// mv.visitLabel(l1); +// mv.visitVarInsn(ALOAD, 0); +// mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); +// mv.visitMethodInsn(INVOKEVIRTUAL, sncpInfoName, "toSimpleString", "()Ljava/lang/String;", false); +// mv.visitLabel(l2); +// mv.visitInsn(ARETURN); +// mv.visitMaxs(1, 1); +// mv.visitEnd(); +// } int i = -1; Uint128 serviceid = serviceid(name, serviceTypeOrImplClass); - final List serviceActions = new ArrayList<>(); + final List serviceActions = new ArrayList<>(); Class serviceImpClass = realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass; for (Map.Entry en : loadMethodActions(serviceImpClass).entrySet()) { - serviceActions.add(new SncpServiceAction(serviceImpClass, en.getValue(), serviceid, en.getKey())); + serviceActions.add(new SncpRemoteAction(serviceImpClass, en.getValue(), serviceid, en.getKey())); } - for (final SncpServiceAction entry : serviceActions) { + for (final SncpRemoteAction entry : serviceActions) { final int index = ++i; final java.lang.reflect.Method method = entry.method; { @@ -943,7 +794,7 @@ public abstract class Sncp { } } mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc); + mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sncp", sncpInfoDesc); MethodDebugVisitor.pushInt(mv, index); @@ -977,7 +828,7 @@ public abstract class Sncp { } } - mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "remote", "(I[Ljava/lang/Object;)Ljava/lang/Object;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, sncpInfoName, "remote", "(I[Ljava/lang/Object;)Ljava/lang/Object;", false); //mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); if (method.getGenericReturnType() == void.class) { mv.visitInsn(POP); @@ -1023,37 +874,17 @@ public abstract class Sncp { RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); try { T service = (T) newClazz.getDeclaredConstructor().newInstance(); - 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)); - } - { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client"); - c.setAccessible(true); - c.set(service, client); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - } - if (messageAgent != null) { - Field c = newClazz.getDeclaredField(FIELDPREFIX + "_messageAgent"); - c.setAccessible(true); - c.set(service, messageAgent); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - if (service instanceof WebSocketNode) { - c = WebSocketNode.class.getDeclaredField("messageAgent"); - c.setAccessible(true); - c.set(service, messageAgent); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); - } - } { Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf"); c.setAccessible(true); c.set(service, conf); RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); } - if (transportFactory != null) { - transportFactory.addSncpService(service); + { + Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncp"); + c.setAccessible(true); + c.set(service, info); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), c); } return service; } catch (Exception ex) { diff --git a/src/main/java/org/redkale/net/sncp/SncpClient.java b/src/main/java/org/redkale/net/sncp/SncpClient.java index 9dfd74b04..9fd882267 100644 --- a/src/main/java/org/redkale/net/sncp/SncpClient.java +++ b/src/main/java/org/redkale/net/sncp/SncpClient.java @@ -3,19 +3,19 @@ */ package org.redkale.net.sncp; -import java.net.InetSocketAddress; +import java.lang.reflect.Type; +import java.net.*; import java.nio.channels.CompletionHandler; import java.util.concurrent.CompletableFuture; -import org.redkale.annotation.Resource; -import org.redkale.convert.Convert; +import org.redkale.convert.*; import org.redkale.convert.bson.BsonConvert; import org.redkale.net.*; import org.redkale.net.client.*; -import org.redkale.net.sncp.SncpServiceInfo.SncpServiceAction; -import org.redkale.util.Traces; +import org.redkale.net.sncp.SncpRemoteInfo.SncpRemoteAction; +import org.redkale.util.*; /** - * SNCP版Client + * SNCP版Client, 一个SncpServer只能对应一个SncpClient * *

* 详情见: https://redkale.org @@ -28,9 +28,6 @@ public class SncpClient extends Client connect(SncpServiceInfo info) { - return super.connect(); + @Override + protected CompletableFuture connect(SocketAddress addr) { + return super.connect(addr); } //只给远程模式调用的 - public T remote(final SncpServiceInfo info, final int index, final Object... params) { + public T remote(final SncpRemoteInfo info, final int index, final Object[] params) { final Convert convert = info.convert; - final SncpServiceAction action = info.actions[index]; + final SncpRemoteAction action = info.actions[index]; CompletionHandler callbackHandler = null; Object callbackHandlerAttach = null; if (action.paramHandlerIndex >= 0) { @@ -72,7 +70,8 @@ public class SncpClient extends Client { if (t == null) { - handler.completed(v == null ? null : convert.convertFrom(action.paramHandlerResultType, v), attach); + //v,length-1为了读掉(byte)0 + handler.completed(v == null ? null : convert.convertFrom(action.paramHandlerResultType, v, 1, v.length - 1), attach); } else { handler.failed(t, attach); } @@ -80,12 +79,14 @@ public class SncpClient extends Client v == null ? null : convert.convertFrom(action.paramHandlerResultType, v)); + //v,length-1为了读掉(byte)0 + return (T) future.thenApply(v -> v == null ? null : convert.convertFrom(action.paramHandlerResultType, v, 1, v.length - 1)); } else { final CompletableFuture returnFuture = action.returnFutureCreator.create(); future.whenComplete((v, t) -> { if (t == null) { - returnFuture.complete(v == null ? null : convert.convertFrom(action.paramHandlerResultType, v)); + //v,length-1为了读掉(byte)0 + returnFuture.complete(v == null ? null : convert.convertFrom(action.paramHandlerResultType, v, 1, v.length - 1)); } else { returnFuture.completeExceptionally(t); } @@ -93,7 +94,8 @@ public class SncpClient extends Client v == null ? null : convert.convertFrom(action.paramHandlerResultType, v)).join(); + //v,length-1为了读掉(byte)0 + return (T) future.thenApply(v -> v == null ? null : convert.convertFrom(action.returnObjectType, v, 1, v.length - 1)).join(); } else { //返回类型为void future.join(); } @@ -101,11 +103,34 @@ public class SncpClient extends Client remote( - final SncpServiceInfo info, - final SncpServiceAction action, + final SncpRemoteInfo info, + final SncpRemoteAction action, final Convert convert, - final Object... params) { - - return null; + final String traceid, + final Object[] params) { + final Type[] myParamTypes = action.paramTypes; + final Class[] myParamClass = action.paramClasses; + if (action.paramAddressSourceIndex >= 0) { + params[action.paramAddressSourceIndex] = this.clientSncpAddress; + } + final long seqid = System.nanoTime(); + final SncpClientRequest requet = new SncpClientRequest(); + Writer writer = null; + if (myParamTypes.length > 0) { + writer = convert.pollWriter(); + for (int i = 0; i < params.length; i++) { //service方法的参数 + Convert bcc = convert; + if (params[i] instanceof org.redkale.service.RetResult) { + org.redkale.convert.Convert cc = ((org.redkale.service.RetResult) params[i]).convert(); + if (cc instanceof BsonConvert) { + bcc = (BsonConvert) cc; + } + } + bcc.convertTo(writer, CompletionHandler.class.isAssignableFrom(myParamClass[i]) ? CompletionHandler.class : myParamTypes[i], params[i]); + } + } + requet.prepare(action.header, seqid, traceid, (ByteTuple) writer); + final SocketAddress addr = action.paramAddressTargetIndex >= 0 ? (SocketAddress) params[action.paramAddressTargetIndex] : info.nextRemoteAddress(); + return super.connect(addr).thenCompose(conn -> writeChannel(conn, requet).thenApply(rs -> rs.getBodyContent())); } } diff --git a/src/main/java/org/redkale/net/sncp/SncpClientRequest.java b/src/main/java/org/redkale/net/sncp/SncpClientRequest.java index bb21b328e..cbe84b636 100644 --- a/src/main/java/org/redkale/net/sncp/SncpClientRequest.java +++ b/src/main/java/org/redkale/net/sncp/SncpClientRequest.java @@ -5,7 +5,7 @@ package org.redkale.net.sncp; import java.util.Objects; import org.redkale.net.client.*; -import org.redkale.util.ByteArray; +import org.redkale.util.*; /** * client版请求 @@ -23,12 +23,12 @@ public class SncpClientRequest extends ClientRequest { private long seqid; - private byte[] bodyContent; + private ByteTuple bodyContent; public SncpClientRequest() { } - public SncpClientRequest prepare(SncpHeader header, long seqid, String traceid, byte[] bodyContent) { + public SncpClientRequest prepare(SncpHeader header, long seqid, String traceid, ByteTuple bodyContent) { super.prepare(); this.header = header; this.seqid = seqid; @@ -52,10 +52,11 @@ public class SncpClientRequest extends ClientRequest { @Override public void writeTo(ClientConnection conn, ByteArray array) { - if (bodyContent == null) { + array.putPlaceholder(SncpHeader.HEADER_SIZE); + if (bodyContent == null || bodyContent.length() == 0) { header.writeTo(array, header.getAddrBytes(), header.getAddrPort(), seqid, 0, 0); } else { - header.writeTo(array, header.getAddrBytes(), header.getAddrPort(), seqid, bodyContent.length, 0); + header.writeTo(array, header.getAddrBytes(), header.getAddrPort(), seqid, bodyContent.length(), 0); array.put(bodyContent); } } @@ -64,7 +65,7 @@ public class SncpClientRequest extends ClientRequest { public String toString() { return getClass().getSimpleName() + "_" + Objects.hashCode(this) + "{" + "header=" + header + ", seqid =" + seqid - + ", body=[" + (bodyContent == null ? -1 : bodyContent.length) + "]" + + ", body=[" + (bodyContent == null ? -1 : bodyContent.length()) + "]" + "}"; } @@ -76,7 +77,7 @@ public class SncpClientRequest extends ClientRequest { return seqid; } - public byte[] getBodyContent() { + public ByteTuple getBodyContent() { return bodyContent; } diff --git a/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java b/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java index 7c71b7572..62640f3b9 100644 --- a/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java +++ b/src/main/java/org/redkale/net/sncp/SncpDispatcherServlet.java @@ -86,7 +86,7 @@ public class SncpDispatcherServlet extends DispatcherServlet actions = new HashMap<>(); - - public SncpDynServlet(final String resourceName, final Class resourceType, final Service service, - final AtomicInteger maxTypeLength, AtomicInteger maxNameLength) { - super(resourceName, resourceType, service); - this.maxTypeLength = maxTypeLength; - this.maxNameLength = maxNameLength; - this.serviceid = Sncp.serviceid(resourceName, resourceType); - RedkaleClassLoader.putReflectionPublicMethods(service.getClass().getName()); - for (Map.Entry en : Sncp.loadMethodActions(resourceType).entrySet()) { - SncpActionServlet action; - try { - action = SncpActionServlet.create(resourceName, resourceType, service, serviceid, en.getKey(), en.getValue()); - } catch (RuntimeException e) { - throw new SncpException(en.getValue() + " create " + SncpActionServlet.class.getSimpleName() + " error", e); - } - actions.put(en.getKey(), action); - } - maxNameLength.set(Math.max(maxNameLength.get(), resourceName.length() + 1)); - maxTypeLength.set(Math.max(maxTypeLength.get(), resourceType.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 SncpDynServlet)) { - return 1; - } - SncpDynServlet o = (SncpDynServlet) 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 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 { - try { - if (response.inNonBlocking()) { - if (action.nonBlocking) { - action.execute(request, response); - } else { - 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); - } - }); - } - } else { - action.execute(request, response); - } - } catch (Throwable t) { - response.getContext().getLogger().log(Level.SEVERE, "sncp execute error(" + request + ")", t); - response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); - } - } - } - - public static abstract class SncpActionServlet extends SncpServlet { - - protected final Method method; - - protected final Uint128 serviceid; - - protected final Uint128 actionid; - - protected final boolean nonBlocking; - - protected final java.lang.reflect.Type[] paramTypes; //第一个元素存放返回类型return type, void的返回参数类型为null, 数组长度为:1+参数个数 - - protected final java.lang.reflect.Type returnObjectType; //返回结果类型 void必须设为null - - protected final int paramHandlerIndex; //>=0表示存在CompletionHandler参数 - - protected final Class paramHandlerClass; //CompletionHandler参数的类型 - - protected final java.lang.reflect.Type paramHandlerResultType; //CompletionHandler.completed第一个参数的类型 - - protected final java.lang.reflect.Type returnFutureResultType; //返回结果的CompletableFuture的结果泛型类型 - - protected 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 handlerFuncClass = null; - java.lang.reflect.Type handlerResultType = null; - try { - final Class[] paramClasses = method.getParameterTypes(); - java.lang.reflect.Type[] genericParams = method.getGenericParameterTypes(); - for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数 - if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) { - handlerFuncIndex = i; - handlerFuncClass = paramClasses[i]; - java.lang.reflect.Type handlerType = TypeToken.getGenericType(genericParams[i], service.getClass()); - if (handlerType instanceof Class) { - handlerResultType = Object.class; - } else if (handlerType instanceof ParameterizedType) { - handlerResultType = TypeToken.getGenericType(((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); - } else { - throw new SncpException(service.getClass() + " had unknown genericType in " + method); - } - if (method.getReturnType() != void.class) { - throw new SncpException(method + " have CompletionHandler type parameter but return type is not void"); - } - break; - } - } - } catch (Throwable ex) { - } - java.lang.reflect.Type[] originalParamTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), service.getClass()); - java.lang.reflect.Type originalReturnType = TypeToken.getGenericType(method.getGenericReturnType(), service.getClass()); - java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1]; - types[0] = originalReturnType; - System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length); - this.paramTypes = types; - this.paramHandlerIndex = handlerFuncIndex; - this.paramHandlerClass = handlerFuncClass; - this.paramHandlerResultType = handlerResultType; - this.returnObjectType = originalReturnType == void.class || originalReturnType == Void.class ? null : originalReturnType; - if (Future.class.isAssignableFrom(method.getReturnType())) { - java.lang.reflect.Type futureType = TypeToken.getGenericType(method.getGenericReturnType(), service.getClass()); - java.lang.reflect.Type returnType = null; - if (futureType instanceof Class) { - returnType = Object.class; - } else if (futureType instanceof ParameterizedType) { - returnType = TypeToken.getGenericType(((ParameterizedType) futureType).getActualTypeArguments()[0], futureType); - } else { - throw new SncpException(service.getClass() + " had unknown return genericType in " + method); - } - this.returnFutureResultType = returnType; - } else { - this.returnFutureResultType = null; - } - NonBlocking non = method.getAnnotation(NonBlocking.class); - if (non == null) { - non = service.getClass().getAnnotation(NonBlocking.class); - } - //Future代替CompletionStage 不容易判断异步 - this.nonBlocking = non == null ? (CompletionStage.class.isAssignableFrom(method.getReturnType()) || this.paramHandlerIndex >= 0) : false; - } - - @Override - public final void execute(SncpRequest request, SncpResponse response) throws IOException { - if (paramHandlerIndex > 0) { - response.paramAsyncHandler(paramHandlerClass, paramHandlerResultType); - } - try { - action(request, response); - } catch (IOException e) { - throw e; - } catch (Throwable t) { - throw new IOException(t); - } - } - - protected abstract void action(SncpRequest request, SncpResponse response) throws Throwable; - - public T service() { - return (T) service; - } - - @Override - public Uint128 getServiceid() { - return serviceid; - } - - public Uint128 getActionid() { - return actionid; - } - - public String actionName() { - return method.getDeclaringClass().getSimpleName() + "." + method.getName(); - } - - /** - *

-         *      public interface TestService extends Service {
-         *
-         *     public boolean change(TestBean bean, String name, int id);
-         *
-         *     public void insert(BooleanHandler handler, TestBean bean, String name, int id);
-         *
-         *     public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
-         *
-         *    public CompletableFuture<String> changeName(TestBean bean, String name, int id);
-         *
-         * }
-         *
-         * @ResourceType(TestService.class)
-         * class TestServiceImpl implements TestService {
-         *
-         *     @Override
-         *     public boolean change(TestBean bean, String name, int id) {
-         *         return false;
-         *     }
-         *
-         *     @Override
-         *     public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
-         *     }
-         *
-         *     @Override
-         *     public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
-         *     }
-         *
-         *     @Override
-         *     public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
-         *         return null;
-         *     }
-         * }
-         *
-         * class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
-         *
-         *     @Override
-         *     public void completed(Boolean result, TestBean attachment) {
-         *     }
-         *
-         *     @Override
-         *     public void failed(Throwable exc, TestBean attachment) {
-         *     }
-         *
-         * }
-         *
-         * class DynActionTestService_change extends SncpActionServlet {
-         *
-         *     public DynActionTestService_change(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
-         *         super(resourceName, resourceType, service, serviceid, actionid, method);
-         *     }
-         *
-         *     @Override
-         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
-         *         Convert<Reader, Writer> convert = request.getConvert();
-         *         Reader in = request.getReader();
-         *         TestBean arg1 = convert.convertFrom(paramTypes[1], in);
-         *         String arg2 = convert.convertFrom(paramTypes[2], in);
-         *         int arg3 = convert.convertFrom(paramTypes[3], in);
-         *         TestService serviceObj = (TestService) service();
-         *         Object rs = serviceObj.change(arg1, arg2, arg3);
-         *         response.finish(boolean.class, rs);
-         *     }
-         * }
-         *
-         * class DynActionTestService_insert extends SncpActionServlet {
-         *
-         *     public DynActionTestService_insert(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
-         *         super(resourceName, resourceType, service, serviceid, actionid, method);
-         *     }
-         *
-         *     @Override
-         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
-         *         Convert<Reader, Writer> convert = request.getConvert();
-         *         Reader in = request.getReader();
-         *         BooleanHandler arg0 = response.getParamAsyncHandler();
-         *         convert.convertFrom(CompletionHandler.class, in);
-         *         TestBean arg1 = convert.convertFrom(paramTypes[2], in);
-         *         String arg2 = convert.convertFrom(paramTypes[3], in);
-         *         int arg3 = convert.convertFrom(paramTypes[4], in);
-         *         TestService serviceObj = (TestService) service();
-         *         serviceObj.insert(arg0, arg1, arg2, arg3);
-         *         response.finishVoid();
-         *     }
-         * }
-         *
-         * class DynActionTestService_update extends SncpActionServlet {
-         *
-         *     public DynActionTestService_update(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
-         *         super(resourceName, resourceType, service, serviceid, actionid, method);
-         *     }
-         *
-         *     @Override
-         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
-         *         Convert<Reader, Writer> convert = request.getConvert();
-         *         Reader in = request.getReader();
-         *         long a1 = convert.convertFrom(paramTypes[1], in);
-         *         short a2 = convert.convertFrom(paramTypes[2], in);
-         *         CompletionHandler a3 = response.getParamAsyncHandler();
-         *         convert.convertFrom(CompletionHandler.class, in);
-         *         TestBean arg1 = convert.convertFrom(paramTypes[4], in);
-         *         String arg2 = convert.convertFrom(paramTypes[5], in);
-         *         int arg3 = convert.convertFrom(paramTypes[6], in);
-         *         TestService serviceObj = (TestService) service();
-         *         serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
-         *         response.finishVoid();
-         *     }
-         * }
-         *
-         * class DynActionTestService_changeName extends SncpActionServlet {
-         *
-         *     public DynActionTestService_changeName(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
-         *         super(resourceName, resourceType, service, serviceid, actionid, method);
-         *     }
-         *
-         *     @Override
-         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
-         *         Convert<Reader, Writer> convert = request.getConvert();
-         *         Reader in = request.getReader();
-         *         TestBean arg1 = convert.convertFrom(paramTypes[1], in);
-         *         String arg2 = convert.convertFrom(paramTypes[2], in);
-         *         int arg3 = convert.convertFrom(paramTypes[3], in);
-         *         TestService serviceObj = (TestService) service();
-         *         CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
-         *         response.finishFuture(paramHandlerResultType, future);
-         *     }
-         * }
-         *
-         * 
- * - * @param resourceName 资源名 - * @param resourceType 资源类 - * @param service Service - * @param serviceid 类ID - * @param actionid 操作ID - * @param method 方法 - * - * @return SncpActionServlet - */ - @SuppressWarnings("unchecked") - public static SncpActionServlet create( - final String resourceName, - final Class resourceType, - final 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 = Convert.class.getName().replace('.', '/'); - final String uint128Desc = Type.getDescriptor(Uint128.class); - final String convertDesc = Type.getDescriptor(Convert.class); - final String readerDesc = Type.getDescriptor(Reader.class); - final String requestName = SncpRequest.class.getName().replace('.', '/'); - final String responseName = SncpResponse.class.getName().replace('.', '/'); - final String requestDesc = Type.getDescriptor(SncpRequest.class); - final String responseDesc = Type.getDescriptor(SncpResponse.class); - final boolean boolReturnTypeFuture = Future.class.isAssignableFrom(method.getReturnType()); - final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid; - - Class newClazz = null; - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; - } catch (Throwable ex) { - } - - 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); - { - 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.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(7, 7); - mv.visitEnd(); - } - String convertFromDesc = "(Ljava/lang/reflect/Type;" + readerDesc + ")Ljava/lang/Object;"; - try { - convertFromDesc = Type.getMethodDescriptor(Convert.class.getMethod("convertFrom", java.lang.reflect.Type.class, Reader.class)); - } catch (Exception ex) { - throw new SncpException(ex); //不可能会发生 - } - { // action方法 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/lang/Throwable"})); - //mv.setDebug(true); - { //Convert - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getConvert", "()" + convertDesc, false); - mv.visitVarInsn(ASTORE, 3); - } - { //Reader - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getReader", "()" + readerDesc, false); - mv.visitVarInsn(ASTORE, 4); - } - int iconst = ICONST_1; - int intconst = 1; - int store = 5; //action的参数个数+2 - final Class[] paramClasses = method.getParameterTypes(); - int[][] codes = new int[paramClasses.length][2]; - int handlerFuncIndex = -1; - for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数 - if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) { - if (boolReturnTypeFuture) { - throw new SncpException(method + " have both CompletionHandler and CompletableFuture"); - } - if (handlerFuncIndex >= 0) { - throw new SncpException(method + " have more than one CompletionHandler type parameter"); - } - Sncp.checkAsyncModifier(paramClasses[i], method); - handlerFuncIndex = i; - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "getParamAsyncHandler", "()Ljava/nio/channels/CompletionHandler;", false); - mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/')); - mv.visitVarInsn(ASTORE, store); - codes[i] = new int[]{ALOAD, store}; - store++; - iconst++; - intconst++; - mv.visitVarInsn(ALOAD, 3); - mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class))); - mv.visitVarInsn(ALOAD, 4); - mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); - mv.visitInsn(POP); - continue; - } - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;"); - - if (intconst < 6) { - mv.visitInsn(ICONST_0 + intconst); - } else if (iconst <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, intconst); - } else if (iconst <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, intconst); - } else { - mv.visitLdcInsn(intconst); - } - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, 4); - - mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); - int load = ALOAD; - int v = 0; - if (paramClasses[i].isPrimitive()) { - int storecode = ISTORE; - load = ILOAD; - if (paramClasses[i] == long.class) { - storecode = LSTORE; - load = LLOAD; - v = 1; - } else if (paramClasses[i] == float.class) { - storecode = FSTORE; - load = FLOAD; - v = 1; - } else if (paramClasses[i] == double.class) { - storecode = DSTORE; - load = DLOAD; - v = 1; - } - Class bigPrimitiveClass = TypeToken.primitiveToWrapper(paramClasses[i]); - String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/'); - try { - Method pm = bigPrimitiveClass.getMethod(paramClasses[i].getSimpleName() + "Value"); - mv.visitTypeInsn(CHECKCAST, bigPrimitiveName); - mv.visitMethodInsn(INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false); - } catch (Exception ex) { - throw new SncpException(ex); //不可能会发生 - } - mv.visitVarInsn(storecode, store); - } else { - mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/')); - mv.visitVarInsn(ASTORE, store); // - } - codes[i] = new int[]{load, store}; - store += v; - iconst++; - intconst++; - store++; - } - { //调用service - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()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(resourceType.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, resourceTypeName, method.getName(), Type.getMethodDescriptor(method), resourceType.isInterface()); - store++; - } - if (method.getReturnType() != void.class) { - final Class returnClass = method.getReturnType(); - if (returnClass.isPrimitive()) { - Class bigClass = TypeToken.primitiveToWrapper(returnClass); - try { - Method vo = bigClass.getMethod("valueOf", returnClass); - mv.visitMethodInsn(INVOKESTATIC, bigClass.getName().replace('.', '/'), vo.getName(), Type.getMethodDescriptor(vo), false); - } catch (Exception ex) { - throw new SncpException(ex); //不可能会发生 - } - } - mv.visitVarInsn(ASTORE, store); //11 - - if (boolReturnTypeFuture) { //返回类型为Future - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureResultType", "Ljava/lang/reflect/Type;"); - mv.visitVarInsn(ALOAD, store); - mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishFuture", "(Ljava/lang/reflect/Type;Ljava/util/concurrent/Future;)V", false); - } else if (handlerFuncIndex >= 0) { //参数有CompletionHandler - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false); - } else { //普通对象 - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", "Ljava/lang/reflect/Type;"); - mv.visitVarInsn(ALOAD, store); - mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finish", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)V", false); - } - } else { //void返回类型 - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false); - } - mv.visitInsn(RETURN); - mv.visitMaxs(8, store); - mv.visitEnd(); - } - cw.visitEnd(); - - byte[] bytes = cw.toByteArray(); - newClazz = new ClassLoader(serviceClass.getClassLoader()) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), newClazz.getField("service")); - } catch (Exception e) { - } - 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); - } - } - } - } - try { - return (SncpActionServlet) newClazz.getConstructors()[0] - .newInstance(resourceName, resourceType, service, serviceid, actionid, method); - } catch (Exception ex) { - throw new SncpException(ex); //不可能会发生 - } - } - } - -} diff --git a/src/main/java/org/redkale/net/sncp/SncpServiceInfo.java b/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java similarity index 82% rename from src/main/java/org/redkale/net/sncp/SncpServiceInfo.java rename to src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java index 2a4aafdca..34db98f8e 100644 --- a/src/main/java/org/redkale/net/sncp/SncpServiceInfo.java +++ b/src/main/java/org/redkale/net/sncp/SncpRemoteInfo.java @@ -3,13 +3,13 @@ */ package org.redkale.net.sncp; -import java.lang.annotation.*; +import java.lang.annotation.Annotation; import java.lang.reflect.*; import java.net.*; -import java.nio.channels.*; +import java.nio.channels.CompletionHandler; import java.util.*; import java.util.concurrent.*; -import org.redkale.convert.*; +import org.redkale.convert.Convert; import org.redkale.mq.*; import static org.redkale.net.sncp.Sncp.loadMethodActions; import org.redkale.service.*; @@ -26,7 +26,7 @@ import org.redkale.util.*; * * @since 2.8.0 */ -public final class SncpServiceInfo { +public final class SncpRemoteInfo { protected final String name; @@ -36,12 +36,17 @@ public final class SncpServiceInfo { protected final int serviceVersion; - protected final SncpServiceAction[] actions; + protected final SncpRemoteAction[] actions; + //MQ模式下此字段才有值 protected final String topic; + //默认值: BsonConvert.root() protected final Convert convert; + //非MQ模式下此字段才有值 + protected final SncpRpcGroups sncpRpcGroups; + //非MQ模式下此字段才有值 protected final SncpClient sncpClient; @@ -51,34 +56,59 @@ public final class SncpServiceInfo { //MQ模式下此字段才有值 protected final SncpMessageClient messageClient; - //远程模式, 可能为null - protected Set remoteGroups; + //MQ模式下此字段才有值, 可能为null + protected String remoteGroup; - //远程模式, 可能为null + //MQ模式下此字段才有值, 可能为null protected Set remoteAddresses; - SncpServiceInfo(String resourceName, Class resourceServiceType, final Class serviceImplClass, Convert convert, - SncpClient sncpClient, MessageAgent messageAgent, SncpMessageClient messageClient) { - this.sncpClient = sncpClient; + SncpRemoteInfo(String resourceName, Class resourceServiceType, Class serviceImplClass, Convert convert, + SncpRpcGroups sncpRpcGroups, SncpClient sncpClient, MessageAgent messageAgent, String remoteGroup) { + Objects.requireNonNull(sncpRpcGroups); this.name = resourceName; this.serviceType = resourceServiceType; this.serviceid = Sncp.serviceid(resourceName, resourceServiceType); this.convert = convert; this.serviceVersion = 0; + this.sncpRpcGroups = sncpRpcGroups; + this.sncpClient = sncpClient; this.messageAgent = messageAgent; + this.remoteGroup = remoteGroup; this.messageClient = messageAgent == null ? null : messageAgent.getSncpMessageClient(); this.topic = messageAgent == null ? null : messageAgent.generateSncpReqTopic(resourceName, resourceServiceType); - final List serviceActions = new ArrayList<>(); + final List serviceActions = new ArrayList<>(); for (Map.Entry en : loadMethodActions(resourceServiceType).entrySet()) { - serviceActions.add(new SncpServiceAction(serviceImplClass, en.getValue(), serviceid, en.getKey())); + serviceActions.add(new SncpRemoteAction(serviceImplClass, en.getValue(), serviceid, en.getKey())); } - this.actions = serviceActions.toArray(new SncpServiceAction[serviceActions.size()]); + this.actions = serviceActions.toArray(new SncpRemoteAction[serviceActions.size()]); } - //只给远程模式调用的 + public InetSocketAddress nextRemoteAddress() { + SncpRpcGroup srg = sncpRpcGroups.getSncpRpcGroup(remoteGroup); + if (srg != null) { + Set addrs = srg.getAddresses(); + if (!addrs.isEmpty()) { + Iterator it = addrs.iterator(); + if (it.hasNext()) { + return it.next(); + } + } + } + throw new SncpException("Not found SocketAddress by remoteGroup = " + remoteGroup); + } + + //由远程模式的DyncRemoveService调用 public T remote(final int index, final Object... params) { - return sncpClient.remote(this, index, params); + if (messageAgent != null) { + return remoteMessage(index, params); + } else { + return sncpClient.remote(this, index, params); + } + } + + private T remoteMessage(final int index, final Object[] params) { + throw new UnsupportedOperationException(); } @Override @@ -93,12 +123,12 @@ public final class SncpServiceInfo { InetSocketAddress clientSncpAddress = sncpClient == null ? null : sncpClient.getClientSncpAddress(); return serviceType.getSimpleName() + "(name = '" + name + "', serviceid = " + serviceid + ", serviceVersion = " + serviceVersion + ", clientaddr = " + (clientSncpAddress == null ? "" : (clientSncpAddress.getHostString() + ":" + clientSncpAddress.getPort())) - + ((remoteGroups == null || remoteGroups.isEmpty()) ? "" : ", remoteGroups = " + remoteGroups) + + ((remoteGroup == null || remoteGroup.isEmpty()) ? "" : ", remoteGroup = " + remoteGroup) + ", actions.size = " + actions.length + ")"; } - public void updateRemoteAddress(Set remoteGroups, Set remoteAddresses) { - this.remoteGroups = remoteGroups; + public void updateRemoteAddress(String remoteGroup, Set remoteAddresses) { + this.remoteGroup = remoteGroup; this.remoteAddresses = remoteAddresses; } @@ -118,7 +148,7 @@ public final class SncpServiceInfo { return serviceVersion; } - public SncpServiceAction[] getActions() { + public SncpRemoteAction[] getActions() { return actions; } @@ -126,15 +156,15 @@ public final class SncpServiceInfo { return topic; } - public Set getRemoteGroups() { - return remoteGroups; + public String getRemoteGroup() { + return remoteGroup; } public Set getRemoteAddresses() { return remoteAddresses; } - public static final class SncpServiceAction { + public static final class SncpRemoteAction { protected final Uint128 actionid; @@ -169,7 +199,7 @@ public final class SncpServiceInfo { protected final SncpHeader header; @SuppressWarnings("unchecked") - SncpServiceAction(final Class serviceImplClass, Method method, Uint128 serviceid, Uint128 actionid) { + SncpRemoteAction(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.returnObjectType = rt == void.class || rt == Void.class ? null : rt; diff --git a/src/main/java/org/redkale/net/sncp/SncpRpcGroup.java b/src/main/java/org/redkale/net/sncp/SncpRpcGroup.java new file mode 100644 index 000000000..577b9cee7 --- /dev/null +++ b/src/main/java/org/redkale/net/sncp/SncpRpcGroup.java @@ -0,0 +1,152 @@ +/* + * + */ +package org.redkale.net.sncp; + +import java.net.InetSocketAddress; +import java.util.*; +import java.util.concurrent.locks.ReentrantLock; +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Utility; + +/** + * 协议地址组合对象, 对应application.xml 中 resources->group 节点信息 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpRpcGroup { + + protected final ReentrantLock lock = new ReentrantLock(); + + @ConvertColumn(index = 1) + protected String name; //地址 + + @ConvertColumn(index = 2) + protected String protocol; //协议 取值范围: TCP、UDP + + @ConvertColumn(index = 3) + protected Set addresses; //地址列表, 对应 resources->group->node节点信息 + + public SncpRpcGroup() { + } + + public SncpRpcGroup(String name, InetSocketAddress... addrs) { + this(name, "TCP", Utility.ofSet(addrs)); + } + + public SncpRpcGroup(String name, Set addrs) { + this(name, "TCP", addrs); + } + + public SncpRpcGroup(String name, String protocol, InetSocketAddress... addrs) { + this(name, protocol, Utility.ofSet(addrs)); + } + + public SncpRpcGroup(String name, String protocol, Set addresses) { + Objects.requireNonNull(name, "rpc.group.name can not null"); + this.name = name; + this.protocol = protocol == null ? "TCP" : protocol; + this.addresses = addresses; + } + + public String getName() { + return name; + } + + public void setName(String name) { + Objects.requireNonNull(name, "rpc.group.name can not null"); + this.name = name; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol == null ? "TCP" : protocol; + } + + public Set getAddresses() { + return addresses; + } + + public Set copyAddresses() { + lock.lock(); + try { + return addresses == null ? null : new LinkedHashSet<>(addresses); + } finally { + lock.unlock(); + } + } + + public void setAddresses(Set addresses) { + this.addresses = addresses; + } + + public boolean containsAddress(InetSocketAddress addr) { + lock.lock(); + try { + if (this.addresses == null) { + return false; + } + return this.addresses.contains(addr); + } finally { + lock.unlock(); + } + } + + public void removeAddress(InetSocketAddress addr) { + if (addr == null) { + return; + } + lock.lock(); + try { + if (this.addresses == null) { + return; + } + this.addresses.remove(addr); + } finally { + lock.unlock(); + } + } + + public void putAddress(InetSocketAddress addr) { + if (addr == null) { + return; + } + lock.lock(); + try { + if (this.addresses == null) { + this.addresses = new LinkedHashSet<>(); + } + this.addresses.add(addr); + } finally { + lock.unlock(); + } + } + + public void putAddress(Set addrs) { + if (addrs == null) { + return; + } + lock.lock(); + try { + if (this.addresses == null) { + this.addresses = new LinkedHashSet<>(); + } + this.addresses.addAll(addrs); + } finally { + lock.unlock(); + } + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpRpcGroups.java b/src/main/java/org/redkale/net/sncp/SncpRpcGroups.java new file mode 100644 index 000000000..28aa7eb25 --- /dev/null +++ b/src/main/java/org/redkale/net/sncp/SncpRpcGroups.java @@ -0,0 +1,62 @@ +/* + * + */ +package org.redkale.net.sncp; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.redkale.boot.ClassFilter; + +/** + * 协议地址组合对象, 对应application.xml 中 resources->group 节点信息 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public class SncpRpcGroups { + + protected final Map sncpRpcGroups = new ConcurrentHashMap<>(); + + public SncpRpcGroup getSncpRpcGroup(String group) { + return sncpRpcGroups.get(group); + } + + public boolean containsGroup(String group) { + return sncpRpcGroups.containsKey(group); + } + + public SncpRpcGroup computeIfAbsent(String group, String protocol) { + return sncpRpcGroups.computeIfAbsent(group, g -> new SncpRpcGroup(group, protocol)); + } + + public String getGroup(InetSocketAddress address) { + for (SncpRpcGroup g : sncpRpcGroups.values()) { + if (g.containsAddress(address)) { + return g.getName(); + } + } + return null; + } + + public boolean isLocalGroup(String sncpGroup, InetSocketAddress sncpAddress, ClassFilter.FilterEntry entry) { + if (sncpGroup != null && !sncpGroup.isEmpty() && sncpGroup.equals(entry.getGroup())) { + return true; + } + if (entry.isEmptyGroup()) { + return true; + } else if (entry.isRemote()) { + return false; + } else { + SncpRpcGroup group = sncpRpcGroups.get(entry.getGroup()); + if (group == null) { + throw new SncpException("Not found group(" + entry.getGroup() + ")"); + } else { + return sncpAddress == null ? false : group.containsAddress(sncpAddress); + } + } + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpServer.java b/src/main/java/org/redkale/net/sncp/SncpServer.java index 616bf8999..6ffe30ac7 100644 --- a/src/main/java/org/redkale/net/sncp/SncpServer.java +++ b/src/main/java/org/redkale/net/sncp/SncpServer.java @@ -6,7 +6,7 @@ package org.redkale.net.sncp; import java.util.List; -import java.util.concurrent.atomic.*; +import java.util.concurrent.atomic.LongAdder; import org.redkale.boot.Application; import org.redkale.net.Server; import org.redkale.net.sncp.SncpContext.SncpContextConfig; @@ -24,10 +24,6 @@ import org.redkale.util.*; @SuppressWarnings("unchecked") public class SncpServer extends Server { - private final AtomicInteger maxTypeLength = new AtomicInteger(); - - private final AtomicInteger maxNameLength = new AtomicInteger(); - public SncpServer() { this(null, System.currentTimeMillis(), null, ResourceFactory.create()); } @@ -103,12 +99,11 @@ public class SncpServer extends Server implements Comparable { +public class SncpServlet extends Servlet implements Comparable { protected final Class serviceType; @@ -26,11 +37,76 @@ public abstract class SncpServlet extends Servlet actions = new HashMap<>(); + + private SncpServlet(String resourceName, Class resourceType, Service service, Uint128 serviceid) { + this.serviceName = resourceName; + this.serviceType = resourceType; + this.service = service; + this.serviceid = serviceid; + } + protected SncpServlet(String resourceName, Class resourceType, Service service) { this.serviceName = resourceName; this.serviceType = resourceType; this.service = service; this._nonBlocking = true; + this.serviceid = Sncp.serviceid(resourceName, resourceType); + + RedkaleClassLoader.putReflectionPublicMethods(service.getClass().getName()); + for (Map.Entry en : Sncp.loadMethodActions(resourceType).entrySet()) { + SncpActionServlet action; + try { + action = SncpActionServlet.create(resourceName, resourceType, service, serviceid, en.getKey(), en.getValue()); + } catch (RuntimeException e) { + throw new SncpException(en.getValue() + " create " + SncpActionServlet.class.getSimpleName() + " error", e); + } + actions.put(en.getKey(), action); + } + } + + @Override + @SuppressWarnings("unchecked") + public void execute(SncpRequest request, SncpResponse response) throws IOException { + 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 { + try { + if (response.inNonBlocking()) { + if (action.nonBlocking) { + action.execute(request, response); + } else { + 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); + } + }); + } + } else { + action.execute(request, response); + } + } catch (Throwable t) { + response.getContext().getLogger().log(Level.SEVERE, "sncp execute error(" + request + ")", t); + response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); + } + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getSimpleName()).append(" (type=").append(serviceType.getName()); + sb.append(", serviceid=").append(serviceid).append(", name='").append(serviceName).append("'"); + sb.append(", actions.size=").append(actions.size() > 9 ? "" : " ").append(actions.size()).append(")"); + return sb.toString(); } public Service getService() { @@ -45,7 +121,39 @@ public abstract class SncpServlet extends Servlet=0表示存在CompletionHandler参数 + + protected final Class paramHandlerClass; //CompletionHandler参数的类型 + + protected final java.lang.reflect.Type paramHandlerResultType; //CompletionHandler.completed第一个参数的类型 + + protected final java.lang.reflect.Type returnFutureResultType; //返回结果的CompletableFuture的结果泛型类型 + + protected SncpActionServlet(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) { + super(resourceName, resourceType, service, serviceid); + this.actionid = actionid; + this.method = method; + + int handlerFuncIndex = -1; + Class handlerFuncClass = null; + java.lang.reflect.Type handlerResultType = null; + try { + final Class[] paramClasses = method.getParameterTypes(); + java.lang.reflect.Type[] genericParams = method.getGenericParameterTypes(); + for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数 + if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) { + handlerFuncIndex = i; + handlerFuncClass = paramClasses[i]; + java.lang.reflect.Type handlerType = TypeToken.getGenericType(genericParams[i], service.getClass()); + if (handlerType instanceof Class) { + handlerResultType = Object.class; + } else if (handlerType instanceof ParameterizedType) { + handlerResultType = TypeToken.getGenericType(((ParameterizedType) handlerType).getActualTypeArguments()[0], handlerType); + } else { + throw new SncpException(service.getClass() + " had unknown genericType in " + method); + } + if (method.getReturnType() != void.class) { + throw new SncpException(method + " have CompletionHandler type parameter but return type is not void"); + } + break; + } + } + } catch (Throwable ex) { + } + java.lang.reflect.Type[] originalParamTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), service.getClass()); + java.lang.reflect.Type originalReturnType = TypeToken.getGenericType(method.getGenericReturnType(), service.getClass()); + java.lang.reflect.Type[] types = new java.lang.reflect.Type[originalParamTypes.length + 1]; + types[0] = originalReturnType; + System.arraycopy(originalParamTypes, 0, types, 1, originalParamTypes.length); + this.paramTypes = types; + this.paramHandlerIndex = handlerFuncIndex; + this.paramHandlerClass = handlerFuncClass; + this.paramHandlerResultType = handlerResultType; + this.returnObjectType = originalReturnType == void.class || originalReturnType == Void.class ? null : originalReturnType; + if (Future.class.isAssignableFrom(method.getReturnType())) { + java.lang.reflect.Type futureType = TypeToken.getGenericType(method.getGenericReturnType(), service.getClass()); + java.lang.reflect.Type returnType = null; + if (futureType instanceof Class) { + returnType = Object.class; + } else if (futureType instanceof ParameterizedType) { + returnType = TypeToken.getGenericType(((ParameterizedType) futureType).getActualTypeArguments()[0], futureType); + } else { + throw new SncpException(service.getClass() + " had unknown return genericType in " + method); + } + this.returnFutureResultType = returnType; + } else { + this.returnFutureResultType = null; + } + NonBlocking non = method.getAnnotation(NonBlocking.class); + if (non == null) { + non = service.getClass().getAnnotation(NonBlocking.class); + } + //Future代替CompletionStage 不容易判断异步 + this.nonBlocking = non == null ? (CompletionStage.class.isAssignableFrom(method.getReturnType()) || this.paramHandlerIndex >= 0) : false; + } + + @Override + public final void execute(SncpRequest request, SncpResponse response) throws IOException { + if (paramHandlerIndex > 0) { + response.paramAsyncHandler(paramHandlerClass, paramHandlerResultType); + } + try { + action(request, response); + } catch (IOException e) { + throw e; + } catch (Throwable t) { + throw new IOException(t); + } + } + + protected abstract void action(SncpRequest request, SncpResponse response) throws Throwable; + + public T service() { + return (T) service; + } + + @Override + public Uint128 getServiceid() { + return serviceid; + } + + public Uint128 getActionid() { + return actionid; + } + + public String actionName() { + return method.getDeclaringClass().getSimpleName() + "." + method.getName(); + } + + /** + *

+         *      public interface TestService extends Service {
+         *
+         *     public boolean change(TestBean bean, String name, int id);
+         *
+         *     public void insert(BooleanHandler handler, TestBean bean, String name, int id);
+         *
+         *     public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
+         *
+         *    public CompletableFuture<String> changeName(TestBean bean, String name, int id);
+         *
+         * }
+         *
+         * @ResourceType(TestService.class)
+         * class TestServiceImpl implements TestService {
+         *
+         *     @Override
+         *     public boolean change(TestBean bean, String name, int id) {
+         *         return false;
+         *     }
+         *
+         *     @Override
+         *     public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
+         *     }
+         *
+         *     @Override
+         *     public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
+         *     }
+         *
+         *     @Override
+         *     public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
+         *         return null;
+         *     }
+         * }
+         *
+         * class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
+         *
+         *     @Override
+         *     public void completed(Boolean result, TestBean attachment) {
+         *     }
+         *
+         *     @Override
+         *     public void failed(Throwable exc, TestBean attachment) {
+         *     }
+         *
+         * }
+         *
+         * class DynActionTestService_change extends SncpActionServlet {
+         *
+         *     public DynActionTestService_change(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
+         *         super(resourceName, resourceType, service, serviceid, actionid, method);
+         *     }
+         *
+         *     @Override
+         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
+         *         Convert<Reader, Writer> convert = request.getConvert();
+         *         Reader in = request.getReader();
+         *         TestBean arg1 = convert.convertFrom(paramTypes[1], in);
+         *         String arg2 = convert.convertFrom(paramTypes[2], in);
+         *         int arg3 = convert.convertFrom(paramTypes[3], in);
+         *         TestService serviceObj = (TestService) service();
+         *         Object rs = serviceObj.change(arg1, arg2, arg3);
+         *         response.finish(boolean.class, rs);
+         *     }
+         * }
+         *
+         * class DynActionTestService_insert extends SncpActionServlet {
+         *
+         *     public DynActionTestService_insert(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
+         *         super(resourceName, resourceType, service, serviceid, actionid, method);
+         *     }
+         *
+         *     @Override
+         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
+         *         Convert<Reader, Writer> convert = request.getConvert();
+         *         Reader in = request.getReader();
+         *         BooleanHandler arg0 = response.getParamAsyncHandler();
+         *         convert.convertFrom(CompletionHandler.class, in);
+         *         TestBean arg1 = convert.convertFrom(paramTypes[2], in);
+         *         String arg2 = convert.convertFrom(paramTypes[3], in);
+         *         int arg3 = convert.convertFrom(paramTypes[4], in);
+         *         TestService serviceObj = (TestService) service();
+         *         serviceObj.insert(arg0, arg1, arg2, arg3);
+         *         response.finishVoid();
+         *     }
+         * }
+         *
+         * class DynActionTestService_update extends SncpActionServlet {
+         *
+         *     public DynActionTestService_update(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
+         *         super(resourceName, resourceType, service, serviceid, actionid, method);
+         *     }
+         *
+         *     @Override
+         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
+         *         Convert<Reader, Writer> convert = request.getConvert();
+         *         Reader in = request.getReader();
+         *         long a1 = convert.convertFrom(paramTypes[1], in);
+         *         short a2 = convert.convertFrom(paramTypes[2], in);
+         *         CompletionHandler a3 = response.getParamAsyncHandler();
+         *         convert.convertFrom(CompletionHandler.class, in);
+         *         TestBean arg1 = convert.convertFrom(paramTypes[4], in);
+         *         String arg2 = convert.convertFrom(paramTypes[5], in);
+         *         int arg3 = convert.convertFrom(paramTypes[6], in);
+         *         TestService serviceObj = (TestService) service();
+         *         serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
+         *         response.finishVoid();
+         *     }
+         * }
+         *
+         * class DynActionTestService_changeName extends SncpActionServlet {
+         *
+         *     public DynActionTestService_changeName(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
+         *         super(resourceName, resourceType, service, serviceid, actionid, method);
+         *     }
+         *
+         *     @Override
+         *     public void action(SncpRequest request, SncpResponse response) throws Throwable {
+         *         Convert<Reader, Writer> convert = request.getConvert();
+         *         Reader in = request.getReader();
+         *         TestBean arg1 = convert.convertFrom(paramTypes[1], in);
+         *         String arg2 = convert.convertFrom(paramTypes[2], in);
+         *         int arg3 = convert.convertFrom(paramTypes[3], in);
+         *         TestService serviceObj = (TestService) service();
+         *         CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
+         *         response.finishFuture(paramHandlerResultType, future);
+         *     }
+         * }
+         *
+         * 
+ * + * @param resourceName 资源名 + * @param resourceType 资源类 + * @param service Service + * @param serviceid 类ID + * @param actionid 操作ID + * @param method 方法 + * + * @return SncpActionServlet + */ + @SuppressWarnings("unchecked") + public static SncpActionServlet create( + final String resourceName, + final Class resourceType, + final 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 = Convert.class.getName().replace('.', '/'); + final String uint128Desc = Type.getDescriptor(Uint128.class); + final String convertDesc = Type.getDescriptor(Convert.class); + final String readerDesc = Type.getDescriptor(Reader.class); + final String requestName = SncpRequest.class.getName().replace('.', '/'); + final String responseName = SncpResponse.class.getName().replace('.', '/'); + final String requestDesc = Type.getDescriptor(SncpRequest.class); + final String responseDesc = Type.getDescriptor(SncpResponse.class); + final boolean boolReturnTypeFuture = Future.class.isAssignableFrom(method.getReturnType()); + final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid; + + Class newClazz = null; + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; + } catch (Throwable ex) { + } + + 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); + { + 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.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(7, 7); + mv.visitEnd(); + } + String convertFromDesc = "(Ljava/lang/reflect/Type;" + readerDesc + ")Ljava/lang/Object;"; + try { + convertFromDesc = Type.getMethodDescriptor(Convert.class.getMethod("convertFrom", java.lang.reflect.Type.class, Reader.class)); + } catch (Exception ex) { + throw new SncpException(ex); //不可能会发生 + } + { // action方法 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/lang/Throwable"})); + //mv.setDebug(true); + { //Convert + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getConvert", "()" + convertDesc, false); + mv.visitVarInsn(ASTORE, 3); + } + { //Reader + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getReader", "()" + readerDesc, false); + mv.visitVarInsn(ASTORE, 4); + } + int iconst = ICONST_1; + int intconst = 1; + int store = 5; //action的参数个数+2 + final Class[] paramClasses = method.getParameterTypes(); + int[][] codes = new int[paramClasses.length][2]; + int handlerFuncIndex = -1; + for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数 + if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) { + if (boolReturnTypeFuture) { + throw new SncpException(method + " have both CompletionHandler and CompletableFuture"); + } + if (handlerFuncIndex >= 0) { + throw new SncpException(method + " have more than one CompletionHandler type parameter"); + } + Sncp.checkAsyncModifier(paramClasses[i], method); + handlerFuncIndex = i; + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "getParamAsyncHandler", "()Ljava/nio/channels/CompletionHandler;", false); + mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/')); + mv.visitVarInsn(ASTORE, store); + codes[i] = new int[]{ALOAD, store}; + store++; + iconst++; + intconst++; + mv.visitVarInsn(ALOAD, 3); + mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class))); + mv.visitVarInsn(ALOAD, 4); + mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); + mv.visitInsn(POP); + continue; + } + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;"); + + if (intconst < 6) { + mv.visitInsn(ICONST_0 + intconst); + } else if (iconst <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, intconst); + } else if (iconst <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, intconst); + } else { + mv.visitLdcInsn(intconst); + } + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, 4); + + mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false); + int load = ALOAD; + int v = 0; + if (paramClasses[i].isPrimitive()) { + int storecode = ISTORE; + load = ILOAD; + if (paramClasses[i] == long.class) { + storecode = LSTORE; + load = LLOAD; + v = 1; + } else if (paramClasses[i] == float.class) { + storecode = FSTORE; + load = FLOAD; + v = 1; + } else if (paramClasses[i] == double.class) { + storecode = DSTORE; + load = DLOAD; + v = 1; + } + Class bigPrimitiveClass = TypeToken.primitiveToWrapper(paramClasses[i]); + String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/'); + try { + Method pm = bigPrimitiveClass.getMethod(paramClasses[i].getSimpleName() + "Value"); + mv.visitTypeInsn(CHECKCAST, bigPrimitiveName); + mv.visitMethodInsn(INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false); + } catch (Exception ex) { + throw new SncpException(ex); //不可能会发生 + } + mv.visitVarInsn(storecode, store); + } else { + mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/')); + mv.visitVarInsn(ASTORE, store); // + } + codes[i] = new int[]{load, store}; + store += v; + iconst++; + intconst++; + store++; + } + { //调用service + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()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(resourceType.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, resourceTypeName, method.getName(), Type.getMethodDescriptor(method), resourceType.isInterface()); + store++; + } + if (method.getReturnType() != void.class) { + final Class returnClass = method.getReturnType(); + if (returnClass.isPrimitive()) { + Class bigClass = TypeToken.primitiveToWrapper(returnClass); + try { + Method vo = bigClass.getMethod("valueOf", returnClass); + mv.visitMethodInsn(INVOKESTATIC, bigClass.getName().replace('.', '/'), vo.getName(), Type.getMethodDescriptor(vo), false); + } catch (Exception ex) { + throw new SncpException(ex); //不可能会发生 + } + } + mv.visitVarInsn(ASTORE, store); //11 + + if (boolReturnTypeFuture) { //返回类型为Future + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureResultType", "Ljava/lang/reflect/Type;"); + mv.visitVarInsn(ALOAD, store); + mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishFuture", "(Ljava/lang/reflect/Type;Ljava/util/concurrent/Future;)V", false); + } else if (handlerFuncIndex >= 0) { //参数有CompletionHandler + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false); + } else { //普通对象 + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", "Ljava/lang/reflect/Type;"); + mv.visitVarInsn(ALOAD, store); + mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finish", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)V", false); + } + } else { //void返回类型 + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false); + } + mv.visitInsn(RETURN); + mv.visitMaxs(8, store); + mv.visitEnd(); + } + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + newClazz = new ClassLoader(serviceClass.getClassLoader()) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), newClazz.getField("service")); + } catch (Exception e) { + } + 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); + } + } + } + } + try { + return (SncpActionServlet) newClazz.getConstructors()[0] + .newInstance(resourceName, resourceType, service, serviceid, actionid, method); + } catch (Exception ex) { + throw new SncpException(ex); //不可能会发生 + } + } } } diff --git a/src/main/java/org/redkale/util/ByteArray.java b/src/main/java/org/redkale/util/ByteArray.java index 284826d37..a140bbf73 100644 --- a/src/main/java/org/redkale/util/ByteArray.java +++ b/src/main/java/org/redkale/util/ByteArray.java @@ -6,9 +6,9 @@ package org.redkale.util; import java.io.*; -import java.nio.*; +import java.nio.ByteBuffer; import java.nio.charset.*; -import java.util.*; +import java.util.Arrays; /** * 简单的byte[]操作类。 @@ -443,6 +443,17 @@ public final class ByteArray implements ByteTuple { return this; } + //类似writeTo(new byte[length]) + public ByteArray putPlaceholder(final int length) { + if (count >= content.length - length) { + byte[] ns = new byte[content.length + Math.max(16, length)]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + count += length; + return this; + } + /** * 写入一个char值 * @@ -887,6 +898,17 @@ public final class ByteArray implements ByteTuple { return this; } + /** + * 写入一组byte值 + * + * @param tuple 内容 + * + * @return ByteArray + */ + public ByteArray put(ByteTuple tuple) { + return put(tuple.content(), tuple.offset(), tuple.length()); + } + /** * 写入一组byte值, content.length 必须不能小于poffset+length * diff --git a/src/main/java/org/redkale/util/Uint128.java b/src/main/java/org/redkale/util/Uint128.java index 9bde6b9f1..46c4534b3 100644 --- a/src/main/java/org/redkale/util/Uint128.java +++ b/src/main/java/org/redkale/util/Uint128.java @@ -75,6 +75,9 @@ public final class Uint128 extends Number implements Comparable { if (obj == null) { return false; } + if (obj == this) { + return true; + } if (getClass() != obj.getClass()) { return false; } @@ -92,7 +95,7 @@ public final class Uint128 extends Number implements Comparable { if (this == ZERO) { return "0"; } - return new String(Utility.binToHex(value)); + return Utility.binToHexString(value); } @Override diff --git a/src/test/java/org/redkale/test/service/ABMainService.java b/src/test/java/org/redkale/test/service/ABMainService.java index b32bd39d2..3c9501dc5 100644 --- a/src/test/java/org/redkale/test/service/ABMainService.java +++ b/src/test/java/org/redkale/test/service/ABMainService.java @@ -5,21 +5,23 @@ */ package org.redkale.test.service; -import java.io.*; -import java.net.*; -import java.nio.*; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; import java.nio.channels.*; +import java.nio.charset.StandardCharsets; import java.util.concurrent.*; import java.util.concurrent.atomic.*; -import java.util.logging.*; -import org.redkale.annotation.*; +import java.util.logging.Level; +import org.redkale.annotation.Resource; import org.redkale.boot.*; -import org.redkale.convert.bson.*; -import org.redkale.convert.json.*; -import org.redkale.net.*; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.AsyncIOGroup; +import org.redkale.net.client.ClientAddress; import org.redkale.net.http.*; import org.redkale.net.sncp.*; -import org.redkale.service.*; +import org.redkale.service.Service; import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.*; @@ -30,85 +32,96 @@ import org.redkale.util.*; @RestService(name = "abmain") public class ABMainService implements Service { + private static final int abport = 8866; + @Resource private BCService bcService; public static void remote(String[] args) throws Throwable { System.out.println("------------------- 远程模式调用 -----------------------------------"); final Application application = Application.create(true); - final int abport = 8888; final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); asyncGroup.start(); - ResourceFactory resFactory = ResourceFactory.create(); - ExecutorService executor = Executors.newSingleThreadExecutor(); - final TransportFactory transFactory = TransportFactory.create(asyncGroup, 0, 0); - transFactory.addGroupInfo("g77", new InetSocketAddress("127.0.0.1", 5577)); - transFactory.addGroupInfo("g88", new InetSocketAddress("127.0.0.1", 5588)); - transFactory.addGroupInfo("g99", new InetSocketAddress("127.0.0.1", 5599)); - + InetSocketAddress sncpAddress = new InetSocketAddress("127.0.0.1", abport); + final SncpClient client = new SncpClient("", asyncGroup, sncpAddress, new ClientAddress(sncpAddress), "TCP", 16, 100); + final ResourceFactory resFactory = ResourceFactory.create(); resFactory.register(JsonConvert.root()); resFactory.register(BsonConvert.root()); + final SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); + rpcGroups.computeIfAbsent("g77", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5577)); + rpcGroups.computeIfAbsent("g88", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5588)); + rpcGroups.computeIfAbsent("g99", "TCP").putAddress(new InetSocketAddress("127.0.0.1", 5599)); //------------------------ 初始化 CService ------------------------------------ - CService cservice = Sncp.createSimpleLocalService(CService.class, null, resFactory, transFactory, new InetSocketAddress("127.0.0.1", 5577), "g77"); + CService cservice = Sncp.createSimpleLocalService(CService.class, resFactory); SncpServer cserver = new SncpServer(); cserver.getResourceFactory().register(application); - cserver.getLogger().setLevel(Level.WARNING); + //cserver.getLogger().setLevel(Level.WARNING); cserver.addSncpServlet(cservice); cserver.init(DefaultAnyValue.create("port", 5577)); cserver.start(); //------------------------ 初始化 BCService ------------------------------------ - BCService bcservice = Sncp.createSimpleLocalService(BCService.class, null, resFactory, transFactory, new InetSocketAddress("127.0.0.1", 5588), "g88"); - CService remoteCService = Sncp.createSimpleRemoteService(CService.class, null, transFactory, new InetSocketAddress("127.0.0.1", 5588), "g77"); - resFactory.inject(remoteCService); - resFactory.register("", remoteCService); + BCService bcservice = Sncp.createSimpleLocalService(BCService.class, resFactory); + CService remoteCService = Sncp.createSimpleRemoteService(CService.class, resFactory, rpcGroups, client, "g77"); + if (remoteCService != null) { + resFactory.inject(remoteCService); + resFactory.register("", remoteCService); + } SncpServer bcserver = new SncpServer(); bcserver.getResourceFactory().register(application); - bcserver.getLogger().setLevel(Level.WARNING); + //bcserver.getLogger().setLevel(Level.WARNING); bcserver.addSncpServlet(bcservice); bcserver.init(DefaultAnyValue.create("port", 5588)); bcserver.start(); //------------------------ 初始化 ABMainService ------------------------------------ - ABMainService service = Sncp.createSimpleLocalService(ABMainService.class, null, resFactory, transFactory, new InetSocketAddress("127.0.0.1", 5599), "g99"); - BCService remoteBCService = Sncp.createSimpleRemoteService(BCService.class, null, transFactory, new InetSocketAddress("127.0.0.1", 5599), "g88"); - resFactory.inject(remoteBCService); - resFactory.register("", remoteBCService); - - HttpServer server = new HttpServer(); - server.getResourceFactory().register(application); - server.getLogger().setLevel(Level.WARNING); - - server.addRestServlet(null, service, null, HttpServlet.class, "/pipes"); + ABMainService service = Sncp.createSimpleLocalService(ABMainService.class, resFactory); + BCService remoteBCService = Sncp.createSimpleRemoteService(BCService.class, resFactory, rpcGroups, client, "g88"); + if (remoteBCService != null) { + resFactory.inject(remoteBCService); + resFactory.register("", remoteBCService); + } resFactory.inject(cservice); resFactory.inject(bcservice); resFactory.inject(service); + HttpServer server = new HttpServer(); + server.getResourceFactory().register(application); + //server.getLogger().setLevel(Level.WARNING); + server.init(DefaultAnyValue.create("port", abport)); + server.addRestServlet(null, service, null, HttpServlet.class, "/pipes"); server.start(); Thread.sleep(100); System.out.println("开始请求"); + + //不声明一个新的HttpClient会导致Utility.postHttpContent操作 + //同一url在Utility里的httpClient会缓存导致调用是吧,应该是httpClient的bug + java.net.http.HttpClient httpClient = java.net.http.HttpClient.newHttpClient(); + System.out.println("httpclient类: " + httpClient.getClass().getName()); //同步方法 - String url = "http://127.0.0.1:" + abport + "/pipes/abmain/syncabtime/张先生"; - System.out.println(Utility.postHttpContent(url)); + String url = "http://127.0.0.1:" + abport + "/pipes/abmain/sab/张先生"; + System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null).join()); //异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime/张先生"; - System.out.println(Utility.postHttpContent(url)); + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc/张先生"; + System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null).join()); //异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime2/张先生"; - System.out.println(Utility.postHttpContent(url)); + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc2/张先生"; + System.out.println(Utility.postHttpContentAsync(httpClient, url, StandardCharsets.UTF_8, null).join()); server.shutdown(); + bcserver.shutdown(); + cserver.shutdown(); } public static void main(String[] args) throws Throwable { + LoggingBaseHandler.initDebugLogConfig(); System.out.println("------------------- 本地模式调用 -----------------------------------"); final Application application = Application.create(true); - final int abport = 8888; ResourceFactory factory = ResourceFactory.create(); ABMainService service = new ABMainService(); @@ -131,16 +144,17 @@ public class ABMainService implements Service { server.start(); Thread.sleep(100); + System.out.println("开始请求"); //同步方法 - String url = "http://127.0.0.1:" + abport + "/pipes/abmain/syncabtime/张先生"; + String url = "http://127.0.0.1:" + abport + "/pipes/abmain/sab/张先生"; System.out.println(Utility.postHttpContent(url)); //异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime/张先生"; + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc/张先生"; System.out.println(Utility.postHttpContent(url)); //异步方法 - url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime2/张先生"; + url = "http://127.0.0.1:" + abport + "/pipes/abmain/abc2/张先生"; System.out.println(Utility.postHttpContent(url)); server.shutdown(); @@ -170,16 +184,17 @@ public class ABMainService implements Service { }); } - @RestMapping(name = "syncabtime") + @RestMapping(name = "sab") public String abCurrentTime(@RestParam(name = "#") final String name) { - String rs = "同步abCurrentTime: " + bcService.bcCurrentTime(name); + System.out.println("准备执行ABMainService.sab方法"); + String rs = "同步abCurrentTime: " + bcService.bcCurrentTime1(name); System.out.println("执行了 ABMainService.abCurrentTime++++同步方法"); return rs; } - @RestMapping(name = "asyncabtime") + @RestMapping(name = "abc") public void abCurrentTime(final CompletionHandler handler, @RestParam(name = "#") final String name) { - bcService.bcCurrentTime(Utility.createAsyncHandler((v, a) -> { + bcService.bcCurrentTime2(Utility.createAsyncHandler((v, a) -> { System.out.println("执行了 ABMainService.abCurrentTime----异步方法"); String rs = "异步abCurrentTime: " + v; if (handler != null) { @@ -192,9 +207,9 @@ public class ABMainService implements Service { }), name); } - @RestMapping(name = "asyncabtime2") + @RestMapping(name = "abc2") public void abCurrentTime(final MyAsyncHandler handler, @RestParam(name = "#") final String name) { - bcService.bcCurrentTime(new MyAsyncHandler() { + bcService.bcCurrentTime3(new MyAsyncHandler() { @Override public int id() { return 1; diff --git a/src/test/java/org/redkale/test/service/BCService.java b/src/test/java/org/redkale/test/service/BCService.java index 9df6ac4bd..2883d648d 100644 --- a/src/test/java/org/redkale/test/service/BCService.java +++ b/src/test/java/org/redkale/test/service/BCService.java @@ -5,10 +5,10 @@ */ package org.redkale.test.service; -import java.nio.channels.*; -import org.redkale.annotation.*; +import java.nio.channels.CompletionHandler; +import org.redkale.annotation.Resource; import org.redkale.service.*; -import org.redkale.util.*; +import org.redkale.util.Utility; /** * @@ -33,16 +33,17 @@ public class BCService implements Service { return serviceType; } - public String bcCurrentTime(final String name) { - String rs = "同步bcCurrentTime: " + cService.ccCurrentTime(name).getResult(); - System.out.println("执行了 BCService.bcCurrentTime++++同步方法"); + public String bcCurrentTime1(final String name) { + System.out.println("准备执行BCService.bcCurrentTime1方法"); + String rs = "同步bcCurrentTime1: " + cService.ccCurrentTime1(name).getResult(); + System.out.println("执行了 BCService.bcCurrentTime1++++同步方法1"); return rs; } - public void bcCurrentTime(final CompletionHandler handler, final String name) { - cService.ccCurrentTime(Utility.createAsyncHandler((v, a) -> { - System.out.println("执行了 BCService.bcCurrentTime----异步方法"); - String rs = "异步bcCurrentTime: " + (v == null ? null : v.getResult()); + public void bcCurrentTime2(final CompletionHandler handler, final String name) { + cService.ccCurrentTime2(Utility.createAsyncHandler((v, a) -> { + System.out.println("执行了 BCService.bcCurrentTime2----异步方法2"); + String rs = "异步bcCurrentTime2: " + (v == null ? null : v.getResult()); if (handler != null) { handler.completed(rs, null); } @@ -53,8 +54,8 @@ public class BCService implements Service { }), name); } - public void bcCurrentTime(final MyAsyncHandler handler, final String name) { - cService.mcCurrentTime(new MyAsyncHandler, Void>() { + public void bcCurrentTime3(final MyAsyncHandler handler, final String name) { + cService.mcCurrentTime3(new MyAsyncHandler, Void>() { @Override public int id() { return 1; @@ -62,8 +63,8 @@ public class BCService implements Service { @Override public void completed(RetResult v, Void a) { - System.out.println("执行了 BCService.bcCurrentTime----异步方法2"); - String rs = "异步bcCurrentTime: " + (v == null ? null : v.getResult()); + System.out.println("执行了 BCService.bcCurrentTime3----异步方法3"); + String rs = "异步bcCurrentTime3: " + (v == null ? null : v.getResult()); if (handler != null) { handler.completed(rs, null); } diff --git a/src/test/java/org/redkale/test/service/CService.java b/src/test/java/org/redkale/test/service/CService.java index fb8200fd2..82c4e6c92 100644 --- a/src/test/java/org/redkale/test/service/CService.java +++ b/src/test/java/org/redkale/test/service/CService.java @@ -5,10 +5,10 @@ */ package org.redkale.test.service; -import java.nio.channels.*; -import org.redkale.annotation.*; +import java.nio.channels.CompletionHandler; +import org.redkale.annotation.Resource; import org.redkale.service.*; -import org.redkale.util.*; +import org.redkale.util.Utility; /** * @@ -30,21 +30,21 @@ public class CService implements Service { return serviceType; } - public RetResult ccCurrentTime(final String name) { - String rs = "同步ccCurrentTime: " + name + ": " + Utility.formatTime(System.currentTimeMillis()); - System.out.println("执行了 CService.ccCurrentTime++++同步方法"); + public RetResult ccCurrentTime1(final String name) { + String rs = "同步ccCurrentTime1: " + name + ": " + Utility.formatTime(System.currentTimeMillis()); + System.out.println("执行了 CService.ccCurrentTime1++++同步方法1"); return new RetResult(rs); } - public void ccCurrentTime(final CompletionHandler, Void> handler, final String name) { - String rs = "异步ccCurrentTime: " + name + ": " + Utility.formatTime(System.currentTimeMillis()); - System.out.println("执行了 CService.ccCurrentTime----异步方法"); + public void ccCurrentTime2(final CompletionHandler, Void> handler, final String name) { + String rs = "异步ccCurrentTime2: " + name + ": " + Utility.formatTime(System.currentTimeMillis()); + System.out.println("执行了 CService.ccCurrentTime2----异步方法2"); if (handler != null) handler.completed(new RetResult(rs), null); } - public void mcCurrentTime(final MyAsyncHandler, Void> handler, final String name) { - String rs = "异步mcCurrentTime: " + name + ": " + Utility.formatTime(System.currentTimeMillis()); - System.out.println("执行了 CService.mcCurrentTime----异步方法2"); + public void mcCurrentTime3(final MyAsyncHandler, Void> handler, final String name) { + String rs = "异步mcCurrentTime3: " + name + ": " + Utility.formatTime(System.currentTimeMillis()); + System.out.println("执行了 CService.mcCurrentTime3----异步方法3"); if (handler != null) handler.completed(new RetResult(rs), null); } } diff --git a/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java b/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java index a9dbe31f7..fc0fe2e1c 100644 --- a/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpClientCodecTest.java @@ -49,11 +49,11 @@ public class SncpClientCodecTest { SncpHeader header = new SncpHeader(sncpAddress, Uint128.ZERO, Uint128.ZERO); SncpClientRequest request = new SncpClientRequest(); ByteArray writeArray = new ByteArray(); - request.prepare(header, 1, "", new byte[20]); + request.prepare(header, 1, "", new ByteArray().putPlaceholder(20)); System.out.println("request.1 = " + request); writeArray.put(new byte[SncpHeader.HEADER_SIZE]); request.writeTo(conn, writeArray); - request.prepare(header, 2, "", new byte[25]); + request.prepare(header, 2, "", new ByteArray().putPlaceholder(25)); System.out.println("request.2 = " + request); writeArray.put(new byte[SncpHeader.HEADER_SIZE]); request.writeTo(conn, writeArray); @@ -63,8 +63,6 @@ public class SncpClientCodecTest { System.out.println("sncp.realBuf = " + realBuf.remaining()); codec.decodeMessages(realBuf, new ByteArray()); System.out.println("respResults.size = " + respResults.size()); - if (!main) { - Assertions.assertEquals(2, respResults.size()); - } + Assertions.assertEquals(2, respResults.size()); } } diff --git a/src/test/java/org/redkale/test/sncp/SncpTest.java b/src/test/java/org/redkale/test/sncp/SncpTest.java index eef805f48..5ab471f2f 100644 --- a/src/test/java/org/redkale/test/sncp/SncpTest.java +++ b/src/test/java/org/redkale/test/sncp/SncpTest.java @@ -14,7 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger; import org.redkale.boot.*; import org.redkale.convert.bson.*; import org.redkale.net.*; -import org.redkale.net.sncp.*; +import org.redkale.net.sncp.SncpServer; import org.redkale.service.Service; import org.redkale.util.*; @@ -76,7 +76,7 @@ public class SncpTest { asyncGroup.start(); final TransportFactory transFactory = TransportFactory.create(asyncGroup, protocol.endsWith(".UDP") ? "UDP" : "TCP", 0, 0); transFactory.addGroupInfo("client", set); - final SncpTestIService service = Sncp.createSimpleRemoteService(SncpTestIService.class, null, transFactory, addr, "client"); + final SncpTestIService service = null;//Sncp.createSimpleRemoteService(SncpTestIService.class, null, transFactory, addr, "client"); factory.inject(service); // SncpTestBean bean = new SncpTestBean(); @@ -171,7 +171,7 @@ public class SncpTest { } final TransportFactory transFactory = TransportFactory.create(asyncGroup, protocol.endsWith(".UDP") ? "UDP" : "TCP", 0, 0); transFactory.addGroupInfo("server", set); - SncpTestIService service = Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, transFactory, addr, "server"); + SncpTestIService service = null;//Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, transFactory, addr, "server"); factory.inject(service); server.addSncpServlet(service); System.out.println(service); @@ -211,7 +211,7 @@ public class SncpTest { final TransportFactory transFactory = TransportFactory.create(asyncGroup, protocol.endsWith(".UDP") ? "UDP" : "TCP", 0, 0); transFactory.addGroupInfo("server", set); - Service service = Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, transFactory, addr, "server"); + Service service = null;//Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, factory, transFactory, addr, "server"); server.addSncpServlet(service); server.init(conf); server.start(); diff --git a/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java b/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java index e84447def..6030b2de0 100644 --- a/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java +++ b/src/test/java/org/redkale/test/sncp/SncpTestServiceImpl.java @@ -13,7 +13,6 @@ import org.redkale.annotation.ResourceType; import org.redkale.net.*; import org.redkale.net.sncp.Sncp; import org.redkale.service.*; -import org.redkale.util.ResourceFactory; /** * @@ -89,7 +88,7 @@ public class SncpTestServiceImpl implements SncpTestIService { final TransportFactory transFactory = TransportFactory.create(asyncGroup, 0, 0); transFactory.addGroupInfo("g70", new InetSocketAddress("127.0.0.1", 7070)); - Service service = Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, ResourceFactory.create(), transFactory, new InetSocketAddress("127.0.0.1", 7070), "g70"); + Service service = null;// Sncp.createSimpleLocalService(SncpTestServiceImpl.class, null, ResourceFactory.create(), transFactory, new InetSocketAddress("127.0.0.1", 7070), "g70"); for (Method method : service.getClass().getDeclaredMethods()) { System.out.println(method); } @@ -98,7 +97,7 @@ public class SncpTestServiceImpl implements SncpTestIService { System.out.println(method); } System.out.println("-----------------------------------"); - service = Sncp.createSimpleRemoteService(SncpTestServiceImpl.class, null, transFactory, new InetSocketAddress("127.0.0.1", 7070), "g70"); + service = null;//Sncp.createSimpleRemoteService(SncpTestServiceImpl.class, null, transFactory, new InetSocketAddress("127.0.0.1", 7070), "g70"); for (Method method : service.getClass().getDeclaredMethods()) { System.out.println(method); } @@ -107,7 +106,7 @@ public class SncpTestServiceImpl implements SncpTestIService { System.out.println(method); } System.out.println("-----------------------------------"); - service = Sncp.createSimpleRemoteService(SncpTestIService.class, null, transFactory, new InetSocketAddress("127.0.0.1", 7070), "g70"); + service = null;//Sncp.createSimpleRemoteService(SncpTestIService.class, null, transFactory, new InetSocketAddress("127.0.0.1", 7070), "g70"); for (Method method : service.getClass().getDeclaredMethods()) { System.out.println(method); } diff --git a/src/test/java/org/redkale/test/sncp/TestService.java b/src/test/java/org/redkale/test/sncp/TestService.java index b1f9c1009..3b50f0284 100644 --- a/src/test/java/org/redkale/test/sncp/TestService.java +++ b/src/test/java/org/redkale/test/sncp/TestService.java @@ -8,8 +8,8 @@ import java.nio.channels.CompletionHandler; import java.util.concurrent.CompletableFuture; import org.redkale.annotation.ResourceType; import org.redkale.convert.*; -import org.redkale.net.sncp.SncpDynServlet.SncpActionServlet; import org.redkale.net.sncp.*; +import org.redkale.net.sncp.SncpServlet.SncpActionServlet; import org.redkale.service.Service; import org.redkale.test.util.TestBean; import org.redkale.util.Uint128;