优化SncpClient的新实现

This commit is contained in:
redkale
2023-03-22 16:02:17 +08:00
parent 358ad80f21
commit 039ed0f569
41 changed files with 2030 additions and 1673 deletions

View File

@@ -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("<group> 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;
}

View File

@@ -86,13 +86,17 @@ public final class ClassFilter<T> {
}
public ClassFilter<T> or(ClassFilter<T> filter) {
if (ors == null) ors = new ArrayList<>();
if (ors == null) {
ors = new ArrayList<>();
}
ors.add(filter);
return this;
}
public ClassFilter<T> and(ClassFilter<T> 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<T> {
public final Set<FilterEntry<T>> getFilterEntrys() {
List<FilterEntry<T>> 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<T> {
public final Set<FilterEntry<T>> getFilterExpectEntrys() {
List<FilterEntry<T>> 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<T> {
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<T> {
}
}
}
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<T> {
&& !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<T> {
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<T> {
*/
@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<T> {
*/
public static final class FilterEntry<T> implements Comparable<FilterEntry<T>> {
private final HashSet<String> groups = new LinkedHashSet<>();
private final String group; //优先级高于remote属性
private final String name;
@@ -412,21 +462,18 @@ public final class ClassFilter<T> {
public FilterEntry(Class<T> 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<T>) o).type.getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
@@ -434,7 +481,7 @@ public final class ClassFilter<T> {
@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<T> {
@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<T> getType() {
@@ -461,16 +512,16 @@ public final class ClassFilter<T> {
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<String> getGroups() {
return groups;
public boolean isRemote() {
return "$remote".equalsIgnoreCase(group);
}
public boolean isAutoload() {
@@ -512,7 +563,9 @@ public final class ClassFilter<T> {
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<T> {
break;
}
}
if (skip) continue;
if (skip) {
continue;
}
}
if (url.getPath().endsWith(".jar")) {
urljares.add(url);
@@ -542,18 +597,36 @@ public final class ClassFilter<T> {
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<T> {
} 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<T> {
if (classes == null) {
classes = new LinkedHashSet<>();
final Set<String> 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<T> {
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<T> {
} 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<T> {
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);
}

View File

@@ -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<String>) 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<AbstractMap.SimpleEntry<String, String[]>> rests = sb == null ? null : new CopyOnWriteArrayList<>();
@@ -265,7 +265,7 @@ public class NodeHttpServer extends NodeServer {
int maxNameLength = 0;
if (rests != null) {
for (AbstractMap.SimpleEntry<String, String[]> 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<String, String[]> 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<String, String[]> 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<String, String[]> 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));
}
}
}

View File

@@ -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<MessageAgent, Service> consumer;
@@ -94,6 +82,7 @@ public abstract class NodeServer {
//远程模式的Service对象集合
protected final Set<Service> remoteServices = new LinkedHashSet<>();
//存在SncpServlet、RestServlet
protected final Map<Service, Servlet> dynServletMap = new LinkedHashMap<>();
//MessageAgent对象集合
@@ -102,6 +91,18 @@ public abstract class NodeServer {
//需要远程模式Service的MessageAgent对象集合
protected final Map<String, MessageAgent> 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 <group> 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<String> 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<String> 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<FilterEntry<? extends Service>> 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<? extends Service> entry : entrys) { //service实现类
final Class<? extends Service> serviceImplClass = entry.getType();
@@ -480,6 +446,9 @@ public abstract class NodeServer {
if (entry.getName().contains("$")) {
throw new RedkaleException("<name> 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<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置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<Service> localServices, Set<Service> 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);

View File

@@ -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<SncpServlet> 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<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName());
}
@Override

View File

@@ -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<TransportGroupInfo> 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();
}
}

View File

@@ -60,8 +60,6 @@ public abstract class ClusterAgent {
protected Set<String> tags;
protected TransportFactory transportFactory;
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
@@ -245,7 +243,7 @@ public abstract class ClusterAgent {
return;
}
Collection<InetSocketAddress> 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;
}

View File

@@ -59,6 +59,7 @@ public abstract class Convert<R extends Reader, W extends Writer> {
public abstract void offerReader(final R reader);
//返回的Writer子类必须实现ByteTuple接口
public abstract W pollWriter();
public abstract void offerWriter(final W write);

View File

@@ -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<K extends Serializable, C extends Context, R extend
postStart();
logger.info(this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(netprotocol) ? "" : ("." + netprotocol)) + " listen: " + (address.getHostString() + ":" + address.getPort())
+ ", cpu: " + Utility.cpus() + ", responsePoolSize: " + responsePoolSize + ", bufferPoolSize: " + bufferPoolSize
+ ", bufferCapacity: " + formatLenth(bufferCapacity) + ", maxbody: " + formatLenth(context.maxBody)
+ ", bufferCapacity: " + formatLenth(bufferCapacity) + ", maxbody: " + formatLenth(context.maxBody) + startExtLog()
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms\r\n");
}
protected String startExtLog() {
return "";
}
protected void postPrepareInit() {
}

View File

@@ -30,6 +30,7 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
@Deprecated(since = "2.8.0")
public final class Transport {
public static final String DEFAULT_NETPROTOCOL = "TCP";

View File

@@ -27,6 +27,7 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
@Deprecated(since = "2.8.0")
public class TransportFactory {
@Comment("默认TCP读取超时秒数")

View File

@@ -19,6 +19,7 @@ import org.redkale.util.Utility;
*
* @author zhangjx
*/
@Deprecated(since = "2.8.0")
public class TransportGroupInfo {
protected final ReentrantLock lock = new ReentrantLock();

View File

@@ -16,6 +16,7 @@ import java.util.concurrent.CompletableFuture;
*
* @author zhangjx
*/
@Deprecated(since = "2.8.0")
public interface TransportStrategy {
/**

View File

@@ -5,6 +5,7 @@
*/
package org.redkale.net.client;
import java.net.SocketAddress;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
@@ -48,23 +49,30 @@ public abstract class Client<C extends ClientConnection<R, P>, 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<R, P>[] connArray; //连接池
//连随机地址模式
final AtomicLong connIndexSeq = new AtomicLong();
protected LongAdder[] connRespWaitings; //连接当前处理数
//连随机地址模式
final ClientConnection<R, P>[] connArray; //连接池
protected AtomicBoolean[] connOpenStates; //conns的标记组当conn不存在或closed状态标记为false
//连随机地址模式
final LongAdder[] connRespWaitings; //连接当前处理数
protected final Queue<CompletableFuture<C>>[] connAcquireWaitings; //连接等待池
//连随机地址模式
final AtomicBoolean[] connOpenStates; //conns的标记组当conn不存在或closed状态标记为false
protected int connLimit = Utility.cpus(); //最大连接数
//连随机地址模式
final int connLimit; //最大连接数
//连随机地址模式
private final Queue<CompletableFuture<C>>[] connAcquireWaitings; //连接等待池
//连指定地址模式
final ConcurrentHashMap<SocketAddress, AddressConnEntry> connAddrEntrys = new ConcurrentHashMap<>();
protected int maxPipelines = DEFAULT_MAX_PIPELINES; //单个连接最大并行处理数
@@ -133,7 +141,7 @@ public abstract class Client<C extends ClientConnection<R, P>, 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<C extends ClientConnection<R, P>, R extends ClientR
conn.dispose(null);
}
}
for (AddressConnEntry<C> 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<C extends ClientConnection<R, P>, R extends ClientR
return connect().thenCompose(conn -> writeChannel(conn, request, respTransfer));
}
public final CompletableFuture<P> sendAsync(SocketAddress addr, R request) {
if (request.workThread == null) {
request.workThread = WorkThread.currWorkThread();
}
return connect(addr).thenCompose(conn -> writeChannel(conn, request));
}
public final <T> CompletableFuture<T> sendAsync(SocketAddress addr, R request, Function<P, T> respTransfer) {
if (request.workThread == null) {
request.workThread = WorkThread.currWorkThread();
}
return connect(addr).thenCompose(conn -> writeChannel(conn, request, respTransfer));
}
protected CompletableFuture<P> writeChannel(ClientConnection conn, R request) {
return conn.writeChannel(request);
}
@@ -233,7 +272,7 @@ public abstract class Client<C extends ClientConnection<R, P>, R extends ClientR
}
final Queue<CompletableFuture<C>> waitQueue = this.connAcquireWaitings[connIndex];
if (this.connOpenStates[connIndex].compareAndSet(false, true)) {
CompletableFuture<C> future = address.createClient(tcp, group, readTimeoutSeconds, writeTimeoutSeconds)
CompletableFuture<C> 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<C extends ClientConnection<R, P>, R extends ClientR
this.connArray[connIndex] = c;
CompletableFuture<C> 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<C extends ClientConnection<R, P>, 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<ClientConnection> 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<C> connect(final SocketAddress addr) {
if (addr == null) {
return connect();
}
final AddressConnEntry<C> entry = connAddrEntrys.computeIfAbsent(addr, a -> new AddressConnEntry());
C ec = entry.connection;
if (ec != null && ec.isOpen()) {
return CompletableFuture.completedFuture(ec);
}
final Queue<CompletableFuture<C>> waitQueue = entry.connAcquireWaitings;
if (entry.connOpenState.compareAndSet(false, true)) {
CompletableFuture<C> 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<C> 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<C extends ClientConnection<R, P>, R extends ClientR
this.writeTimeoutSeconds = writeTimeoutSeconds;
}
protected static class AddressConnEntry<C> {
public C connection;
public final LongAdder connRespWaiting = new LongAdder();
public final AtomicBoolean connOpenState = new AtomicBoolean();
public final Queue<CompletableFuture<C>> connAcquireWaitings = new ConcurrentLinkedDeque();
AddressConnEntry() {
}
}
}

View File

@@ -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<AsyncConnection> 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<WeightAddress> ws) {

View File

@@ -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<R extends ClientRequest, P> 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<R extends ClientRequest, P> implements Co
final ConcurrentLinkedQueue<ClientFuture> pauseRequests = new ConcurrentLinkedQueue<>();
private final Client.AddressConnEntry connEntry;
protected final AsyncConnection channel;
private final ClientCodec<R, P> codec;
@@ -64,7 +67,8 @@ public abstract class ClientConnection<R extends ClientRequest, P> 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<R extends ClientRequest, P> 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<R extends ClientRequest, P> implements Co
return channel;
}
public SocketAddress getRemoteAddress() {
return channel.getRemoteAddress();
}
public long getDoneRequestCounter() {
return doneRequestCounter.longValue();
}

View File

@@ -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.*;

View File

@@ -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<String, HttpContext, HttpRequest, HttpRes
private final ReentrantLock groupLock = new ReentrantLock();
private final ReentrantLock addLock = new ReentrantLock();
private WebSocketAsyncGroup asyncGroup;
//配置<executor threads="0"> APP_EXECUTOR资源为null
@@ -95,6 +97,11 @@ public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpRes
}
}
@Override
protected String startExtLog() {
return context.lazyHeaders ? ", lazyHeaders: true" : "";
}
public List<HttpServlet> getHttpServlets() {
return this.dispatcher.getServlets();
}
@@ -241,7 +248,13 @@ public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpRes
*
* @return RestServlet
*/
public <S extends WebSocket, T extends WebSocketServlet> T addRestWebSocketServlet(final ClassLoader classLoader, final Class<S> webSocketType, MessageAgent messageAgent, final String prefix, final AnyValue conf) {
public <S extends WebSocket, T extends WebSocketServlet> T addRestWebSocketServlet(
final ClassLoader classLoader,
final Class<S> 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<String, HttpContext, HttpRequest, HttpRes
*
* @return RestServlet
*/
public <S extends Service, T extends HttpServlet> T addRestServlet(final ClassLoader classLoader, final S service, final Class userType, final Class<T> baseServletType, final String prefix) {
public <S extends Service, T extends HttpServlet> T addRestServlet(
final ClassLoader classLoader,
final S service,
final Class userType,
final Class<T> baseServletType,
final String prefix) {
return addRestServlet(classLoader, null, service, userType, baseServletType, prefix);
}
@@ -281,72 +300,72 @@ public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpRes
* @return RestServlet
*/
@SuppressWarnings("unchecked")
public <S extends Service, T extends HttpServlet> T addRestServlet(final ClassLoader classLoader, final String name, final S service, final Class userType, final Class<T> baseServletType, final String prefix) {
public <S extends Service, T extends HttpServlet> T addRestServlet(
final ClassLoader classLoader,
final String name,
final S service,
final Class userType,
final Class<T> 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<S> 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<S> 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;
}

View File

@@ -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<String, Service> 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<String> 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<String> 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);

View File

@@ -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<Void> 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<Void> 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<Void> 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<List<String>> 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<Set<WebSocketAddress>> 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<WebSocketAddress> rs = new LinkedHashSet<>();
@@ -208,8 +226,12 @@ public abstract class WebSocketNode {
public CompletableFuture<Map<WebSocketAddress, List<String>>> getRpcNodeWebSocketAddresses(final Serializable userid) {
CompletableFuture<Set<WebSocketAddress>> sncpFuture = getRpcNodeAddresses(userid);
return sncpFuture.thenCompose((Collection<WebSocketAddress> 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<Map<WebSocketAddress, List<String>>> future = null;
for (final WebSocketAddress nodeAddress : addrs) {
CompletableFuture<Map<WebSocketAddress, List<String>>> mapFuture = getWebSocketAddresses(nodeAddress.getTopic(), nodeAddress.getAddr(), userid)
@@ -244,13 +266,21 @@ public abstract class WebSocketNode {
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : CompletableFuture.completedFuture(this.localEngine.getLocalUserSize());
tryAcquireSemaphore();
CompletableFuture<Set<WebSocketAddress>> 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<Integer> 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<Integer> 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<List<String>> listFuture = this.source.keysStartsWithAsync(WS_SOURCE_KEY_USERID_PREFIX);
CompletableFuture<Set<String>> 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<Boolean> existsWebSocket(final Serializable userid) {
if (userid instanceof WebSocketUserAddress) return existsWebSocket((WebSocketUserAddress) userid);
if (userid instanceof WebSocketUserAddress) {
return existsWebSocket((WebSocketUserAddress) userid);
}
CompletableFuture<Boolean> 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<Set<WebSocketAddress>> 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<Boolean> 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<Boolean> 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<Boolean> 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<WebSocketAddress> 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<Boolean> 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<Integer> forceCloseWebSocket(final Serializable userid, final WebSocketUserAddress userAddress) {
CompletableFuture<Integer> 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<WebSocketAddress> 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<Integer> remoteFuture = addrsFuture.thenCompose((Collection<WebSocketAddress> 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<Integer> 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<Integer> 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<Map<String, Set<WebSocketAddress>>> 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<WebSocketAddress, List<Serializable>> addrUsers = new HashMap<>();
@@ -604,8 +686,12 @@ public abstract class WebSocketNode {
*/
@Local
public CompletableFuture<Integer> 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<Integer> 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<Integer> 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<Set<WebSocketAddress>> 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<Integer> 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<Integer> 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<Integer> 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<Serializable> set = new HashSet<>();
for (WebSocketUserAddress userAddress : useraddrs) {
set.add(userAddress.userid());
@@ -808,7 +914,9 @@ public abstract class WebSocketNode {
*/
@Local
public CompletableFuture<Integer> 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<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalMessage(wsrange, message, last);
tryAcquireSemaphore();
CompletableFuture<Set<WebSocketAddress>> 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<Integer> 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<Integer> 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<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalAction(action);
tryAcquireSemaphore();
CompletableFuture<Set<WebSocketAddress>> 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<Integer> 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<Integer> 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<Integer> 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<Map<String, Set<WebSocketAddress>>> 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<WebSocketAddress, List<Serializable>> addrUsers = new HashMap<>();
@@ -934,7 +1064,9 @@ public abstract class WebSocketNode {
*/
@Local
public CompletableFuture<Integer> 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<Integer> 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<Set<WebSocketAddress>> 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<Integer> 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<Integer> 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();
}
}
}

View File

@@ -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<SncpServiceAction> methodens = new ArrayList<>();
final List<SncpRemoteAction> methodens = new ArrayList<>();
//------------------------------------------------------------------------------
for (Map.Entry<Uint128, Method> 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> 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<byte[]> remote0(final CompletionHandler handler, final Transport transport, final SocketAddress addr0, final SncpServiceAction action, final Object... params) {
private CompletableFuture<byte[]> 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
}

View File

@@ -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 <T extends Service> SncpServiceInfo createSncpServiceInfo(String resourceName,
Class<T> resourceServiceType, Class<T> serviceImplClass, Convert convert, SncpClient sncpClient, MessageAgent messageAgent, SncpMessageClient messageClient) {
return new SncpServiceInfo(resourceName, resourceServiceType, serviceImplClass, convert, sncpClient, messageAgent, messageClient);
public static <T extends Service> SncpRemoteInfo createSncpRemoteInfo(String resourceName,
Class<T> resourceServiceType, Class<T> 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<String> groups, final Collection<InetSocketAddress> 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 {
/**
* <blockquote><pre>
* public class TestService implements Service{
* public class TestService implements Service {
*
* public String findSomeThing(){
* return "hello";
@@ -440,16 +383,10 @@ public abstract class Sncp {
* &#64;Resource(name = "")
* &#64;SncpDyn(remote = false)
* &#64;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;
*
* &#64;Override
* public String toString() {
* return _redkale_selfstring == null ? super.toString() : _redkale_selfstring;
* }
* }
* </pre></blockquote>
*
@@ -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, "<init>", "()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<T>) newClazz;
}
public static <T extends Service> T createSimpleLocalService(final Class<T> 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 extends Service> T createSimpleLocalService(Class<T> serviceImplClass, ResourceFactory resourceFactory) {
return createLocalService(null, "", serviceImplClass, resourceFactory, null, null, null, null, null);
}
/**
*
* 创建本地模式Service实例
*
* @param <T> 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 <T> 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<T> serviceImplClass,
final MessageAgent messageAgent,
final ResourceFactory resourceFactory,
final TransportFactory transportFactory,
final InetSocketAddress clientSncpAddress,
final Set<String> 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 extends Service> T createSimpleRemoteService(final Class<T> 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 extends Service> T createSimpleRemoteService(Class<T> 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 {
* &#64;Resource(name = "")
* &#64;SncpDyn(remote = true)
* &#64;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;
*
* &#64;Override
* &#64;Override
* public void createSomeThing(TestBean bean){
* _redkale_client.remote(_redkale_sncpInfo, 0, bean);
* _redkale_client.remote(_redkale_sncp, 0, bean);
* }
*
* &#64;Override
* public String findSomeThing(){
* return _redkale_client.remote(_redkale_sncpInfo, 1);
* return (String)_redkale_client.remote(_redkale_sncp, 1);
* }
*
* &#64;Override
* public String updateSomeThing(String id){
* return _redkale_client.remote(_redkale_sncpInfo, 2, id);
* return (String)_redkale_client.remote(_redkale_sncp, 2, id);
* }
* }
* </pre></blockquote>
@@ -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 extends Service> T createRemoteService(
final ClassLoader classLoader,
final String name,
final Class<T> serviceTypeOrImplClass,
final MessageAgent messageAgent,
final TransportFactory transportFactory,
final InetSocketAddress clientAddress,
final Set<String> 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<String> 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<SncpServiceAction> serviceActions = new ArrayList<>();
final List<SncpRemoteAction> serviceActions = new ArrayList<>();
Class serviceImpClass = realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass;
for (Map.Entry<Uint128, Method> 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) {

View File

@@ -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
*
* <p>
* 详情见: https://redkale.org
@@ -28,9 +28,6 @@ public class SncpClient extends Client<SncpClientConnection, SncpClientRequest,
private final InetSocketAddress clientSncpAddress;
@Resource
protected BsonConvert bsonConvert;
public SncpClient(String name, AsyncGroup group, InetSocketAddress clientSncpAddress, ClientAddress address, String netprotocol, int maxConns, int maxPipelines) {
super(name, group, "TCP".equalsIgnoreCase(netprotocol), address, maxConns, maxPipelines, null, null, null); //maxConns
this.clientSncpAddress = clientSncpAddress;
@@ -45,14 +42,15 @@ public class SncpClient extends Client<SncpClientConnection, SncpClientRequest,
return clientSncpAddress;
}
protected CompletableFuture<SncpClientConnection> connect(SncpServiceInfo info) {
return super.connect();
@Override
protected CompletableFuture<SncpClientConnection> connect(SocketAddress addr) {
return super.connect(addr);
}
//只给远程模式调用的
public <T> T remote(final SncpServiceInfo info, final int index, final Object... params) {
public <T> 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<SncpClientConnection, SncpClientRequest,
} else {
future.whenComplete((v, t) -> {
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<SncpClientConnection, SncpClientRequest,
}
} else if (action.returnFutureClass != null) { //返回类型为CompletableFuture
if (action.returnFutureClass == CompletableFuture.class) {
return (T) future.thenApply(v -> 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<SncpClientConnection, SncpClientRequest,
return (T) returnFuture;
}
} else if (action.returnObjectType != null) { //返回类型为JavaBean
return (T) future.thenApply(v -> 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<SncpClientConnection, SncpClientRequest,
}
private CompletableFuture<byte[]> 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()));
}
}

View File

@@ -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;
}

View File

@@ -86,7 +86,7 @@ public class SncpDispatcherServlet extends DispatcherServlet<Uint128, SncpContex
response.finish(pongBytes);
return;
}
SncpServlet servlet = (SncpServlet) mappingServlet(request.getHeader().getServiceid());
SncpServlet servlet = mappingServlet(request.getHeader().getServiceid());
if (servlet == null) {
response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); //无效serviceid
} else {

View File

@@ -1,642 +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.net.sncp;
import java.io.*;
import java.lang.reflect.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import org.redkale.annotation.*;
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
import org.redkale.asm.*;
import static org.redkale.asm.Opcodes.*;
import org.redkale.asm.Type;
import org.redkale.convert.*;
import org.redkale.convert.Reader;
import org.redkale.convert.bson.*;
import org.redkale.service.*;
import org.redkale.util.*;
/**
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public final class SncpDynServlet extends SncpServlet {
private final AtomicInteger maxTypeLength;
private final AtomicInteger maxNameLength;
private final Uint128 serviceid;
private final HashMap<Uint128, SncpActionServlet> 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<Uint128, Method> 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<? extends CompletionHandler> 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 extends Service> T service() {
return (T) service;
}
@Override
public Uint128 getServiceid() {
return serviceid;
}
public Uint128 getActionid() {
return actionid;
}
public String actionName() {
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
}
/**
* <blockquote><pre>
* public interface TestService extends Service {
*
* public boolean change(TestBean bean, String name, int id);
*
* public void insert(BooleanHandler handler, TestBean bean, String name, int id);
*
* public void update(long show, short v2, CompletionHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id);
*
* public CompletableFuture&#60;String&#62; changeName(TestBean bean, String name, int id);
*
* }
*
* &#064;ResourceType(TestService.class)
* class TestServiceImpl implements TestService {
*
* &#064;Override
* public boolean change(TestBean bean, String name, int id) {
* return false;
* }
*
* &#064;Override
* public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
* }
*
* &#064;Override
* public void update(long show, short v2, CompletionHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id) {
* }
*
* &#064;Override
* public CompletableFuture&#60;String&#62; changeName(TestBean bean, String name, int id) {
* return null;
* }
* }
*
* class BooleanHandler implements CompletionHandler&#60;Boolean, TestBean&#62; {
*
* &#064;Override
* public void completed(Boolean result, TestBean attachment) {
* }
*
* &#064;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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; 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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; 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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; 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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; convert = request.getConvert();
* Reader in = request.getReader();
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
* String arg2 = convert.convertFrom(paramTypes[2], in);
* int arg3 = convert.convertFrom(paramTypes[3], in);
* TestService serviceObj = (TestService) service();
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
* response.finishFuture(paramHandlerResultType, future);
* }
* }
*
* </pre></blockquote>
*
* @param resourceName 资源名
* @param resourceType 资源类
* @param 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, "<init>", "(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, "<init>", "(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); //不可能会发生
}
}
}
}

View File

@@ -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<T extends Service> {
public final class SncpRemoteInfo<T extends Service> {
protected final String name;
@@ -36,12 +36,17 @@ public final class SncpServiceInfo<T extends Service> {
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<T extends Service> {
//MQ模式下此字段才有值
protected final SncpMessageClient messageClient;
//远程模式, 可能为null
protected Set<String> remoteGroups;
//MQ模式下此字段才有值, 可能为null
protected String remoteGroup;
//远程模式, 可能为null
//MQ模式下此字段才有值, 可能为null
protected Set<InetSocketAddress> remoteAddresses;
SncpServiceInfo(String resourceName, Class<T> resourceServiceType, final Class<T> serviceImplClass, Convert convert,
SncpClient sncpClient, MessageAgent messageAgent, SncpMessageClient messageClient) {
this.sncpClient = sncpClient;
SncpRemoteInfo(String resourceName, Class<T> resourceServiceType, Class<T> 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<SncpServiceAction> serviceActions = new ArrayList<>();
final List<SncpRemoteAction> serviceActions = new ArrayList<>();
for (Map.Entry<Uint128, Method> 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<InetSocketAddress> addrs = srg.getAddresses();
if (!addrs.isEmpty()) {
Iterator<InetSocketAddress> it = addrs.iterator();
if (it.hasNext()) {
return it.next();
}
}
}
throw new SncpException("Not found SocketAddress by remoteGroup = " + remoteGroup);
}
//由远程模式的DyncRemoveService调用
public <T> 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> T remoteMessage(final int index, final Object[] params) {
throw new UnsupportedOperationException();
}
@Override
@@ -93,12 +123,12 @@ public final class SncpServiceInfo<T extends Service> {
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<String> remoteGroups, Set<InetSocketAddress> remoteAddresses) {
this.remoteGroups = remoteGroups;
public void updateRemoteAddress(String remoteGroup, Set<InetSocketAddress> remoteAddresses) {
this.remoteGroup = remoteGroup;
this.remoteAddresses = remoteAddresses;
}
@@ -118,7 +148,7 @@ public final class SncpServiceInfo<T extends Service> {
return serviceVersion;
}
public SncpServiceAction[] getActions() {
public SncpRemoteAction[] getActions() {
return actions;
}
@@ -126,15 +156,15 @@ public final class SncpServiceInfo<T extends Service> {
return topic;
}
public Set<String> getRemoteGroups() {
return remoteGroups;
public String getRemoteGroup() {
return remoteGroup;
}
public Set<InetSocketAddress> 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<T extends Service> {
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;

View File

@@ -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-&#62;group 节点信息
*
* <p>
* 详情见: 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<InetSocketAddress> addresses; //地址列表, 对应 resources-&#62;group-&#62;node节点信息
public SncpRpcGroup() {
}
public SncpRpcGroup(String name, InetSocketAddress... addrs) {
this(name, "TCP", Utility.ofSet(addrs));
}
public SncpRpcGroup(String name, Set<InetSocketAddress> 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<InetSocketAddress> 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<InetSocketAddress> getAddresses() {
return addresses;
}
public Set<InetSocketAddress> copyAddresses() {
lock.lock();
try {
return addresses == null ? null : new LinkedHashSet<>(addresses);
} finally {
lock.unlock();
}
}
public void setAddresses(Set<InetSocketAddress> 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<InetSocketAddress> 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);
}
}

View File

@@ -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-&#62;group 节点信息
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.8.0
*/
public class SncpRpcGroups {
protected final Map<String, SncpRpcGroup> 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);
}
}
}
}

View File

@@ -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<Uint128, SncpContext, SncpRequest, SncpResponse, SncpServlet> {
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<Uint128, SncpContext, SncpRequest, SncpRe
return ((SncpDispatcherServlet) this.dispatcher).removeSncpServlet(sncpService);
}
public SncpDynServlet addSncpServlet(Service sncpService) {
public SncpServlet addSncpServlet(Service sncpService) {
if (!Sncp.isSncpDyn(sncpService)) {
throw new SncpException(sncpService + " is not sncp dynamic-gen service");
}
SncpDynServlet sds = new SncpDynServlet(Sncp.getResourceName(sncpService),
Sncp.getResourceType(sncpService), sncpService, maxTypeLength, maxNameLength);
SncpServlet sds = new SncpServlet(Sncp.getResourceName(sncpService), Sncp.getResourceType(sncpService), sncpService);
this.dispatcher.addServlet(sds, null, Sncp.getResourceConf(sncpService));
return sds;
}

View File

@@ -5,11 +5,22 @@
*/
package org.redkale.net.sncp;
import java.util.Objects;
import java.io.IOException;
import java.lang.reflect.*;
import java.nio.channels.CompletionHandler;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import org.redkale.annotation.NonBlocking;
import 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.convert.bson.BsonFactory;
import org.redkale.net.*;
import org.redkale.service.Service;
import org.redkale.util.Uint128;
import org.redkale.util.*;
/**
*
@@ -18,7 +29,7 @@ import org.redkale.util.Uint128;
*
* @author zhangjx
*/
public abstract class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse> implements Comparable<SncpServlet> {
public class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse> implements Comparable<SncpServlet> {
protected final Class serviceType;
@@ -26,11 +37,76 @@ public abstract class SncpServlet extends Servlet<SncpContext, SncpRequest, Sncp
protected final Service service;
protected final Uint128 serviceid;
private final HashMap<Uint128, SncpActionServlet> 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<Uint128, Method> 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<SncpContext, SncpRequest, Sncp
return serviceType;
}
public abstract Uint128 getServiceid();
public Uint128 getServiceid() {
return serviceid;
}
public int getActionSize() {
return actions.size();
}
@Override
public int compareTo(SncpServlet other) {
if (!(other instanceof SncpServlet)) {
return 1;
}
SncpServlet o = other;
int rs = 0;
if (this.serviceType == null) {
rs = o.serviceType == null ? 0 : -1;
} else if (o.serviceType == null) {
rs = 1;
} else {
rs = this.serviceType.getName().compareTo(o.serviceType.getName());
}
if (rs == 0) {
if (this.serviceName == null) {
rs = o.serviceName == null ? 0 : -1;
} else if (o.serviceName == null) {
rs = 1;
} else {
rs = this.serviceName.compareTo(o.serviceName);
}
}
return rs;
}
protected ExecutorService getExecutor() {
Thread thread = Thread.currentThread();
@@ -68,8 +176,512 @@ public abstract class SncpServlet extends Servlet<SncpContext, SncpRequest, Sncp
return Objects.hashCode(getServiceid());
}
@Override
public int compareTo(SncpServlet o) {
return 0;
public static abstract class SncpActionServlet extends SncpServlet {
protected final Method method;
protected final Uint128 actionid;
protected final boolean nonBlocking;
protected final java.lang.reflect.Type[] paramTypes; //第一个元素存放返回类型return type void的返回参数类型为null, 数组长度为:1+参数个数
protected final java.lang.reflect.Type returnObjectType; //返回结果类型 void必须设为null
protected final int paramHandlerIndex; //>=0表示存在CompletionHandler参数
protected final Class<? extends CompletionHandler> paramHandlerClass; //CompletionHandler参数的类型
protected final java.lang.reflect.Type paramHandlerResultType; //CompletionHandler.completed第一个参数的类型
protected final java.lang.reflect.Type returnFutureResultType; //返回结果的CompletableFuture的结果泛型类型
protected 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 extends Service> T service() {
return (T) service;
}
@Override
public Uint128 getServiceid() {
return serviceid;
}
public Uint128 getActionid() {
return actionid;
}
public String actionName() {
return method.getDeclaringClass().getSimpleName() + "." + method.getName();
}
/**
* <blockquote><pre>
* public interface TestService extends Service {
*
* public boolean change(TestBean bean, String name, int id);
*
* public void insert(BooleanHandler handler, TestBean bean, String name, int id);
*
* public void update(long show, short v2, CompletionHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id);
*
* public CompletableFuture&#60;String&#62; changeName(TestBean bean, String name, int id);
*
* }
*
* &#064;ResourceType(TestService.class)
* class TestServiceImpl implements TestService {
*
* &#064;Override
* public boolean change(TestBean bean, String name, int id) {
* return false;
* }
*
* &#064;Override
* public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
* }
*
* &#064;Override
* public void update(long show, short v2, CompletionHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id) {
* }
*
* &#064;Override
* public CompletableFuture&#60;String&#62; changeName(TestBean bean, String name, int id) {
* return null;
* }
* }
*
* class BooleanHandler implements CompletionHandler&#60;Boolean, TestBean&#62; {
*
* &#064;Override
* public void completed(Boolean result, TestBean attachment) {
* }
*
* &#064;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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; 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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; 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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; 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);
* }
*
* &#064;Override
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
* Convert&#60;Reader, Writer&#62; convert = request.getConvert();
* Reader in = request.getReader();
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
* String arg2 = convert.convertFrom(paramTypes[2], in);
* int arg3 = convert.convertFrom(paramTypes[3], in);
* TestService serviceObj = (TestService) service();
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
* response.finishFuture(paramHandlerResultType, future);
* }
* }
*
* </pre></blockquote>
*
* @param resourceName 资源名
* @param resourceType 资源类
* @param 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, "<init>", "(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, "<init>", "(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); //不可能会发生
}
}
}
}

View File

@@ -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
*

View File

@@ -75,6 +75,9 @@ public final class Uint128 extends Number implements Comparable<Uint128> {
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<Uint128> {
if (this == ZERO) {
return "0";
}
return new String(Utility.binToHex(value));
return Utility.binToHexString(value);
}
@Override