优化SncpClient的新实现
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.redkale.util.*;
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Deprecated(since = "2.8.0")
|
||||
public class TransportFactory {
|
||||
|
||||
@Comment("默认TCP读取超时秒数")
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Deprecated(since = "2.8.0")
|
||||
public interface TransportStrategy {
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.*;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
* @Resource(name = "")
|
||||
* @SncpDyn(remote = false)
|
||||
* @ResourceType(TestService.class)
|
||||
* public final class _DynLocalTestService extends TestService{
|
||||
* public final class _DynLocalTestService extends TestService {
|
||||
*
|
||||
* private AnyValue _redkale_conf;
|
||||
* private AnyValue _redkale_conf;
|
||||
*
|
||||
* private OldSncpClient _redkale_client;
|
||||
*
|
||||
* @Override
|
||||
* public String toString() {
|
||||
* return _redkale_selfstring == null ? super.toString() : _redkale_selfstring;
|
||||
* }
|
||||
* }
|
||||
* </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 {
|
||||
* @Resource(name = "")
|
||||
* @SncpDyn(remote = true)
|
||||
* @ResourceType(TestService.class)
|
||||
* public final class _DynRemoteTestService extends TestService{
|
||||
* public final class _DynRemoteTestService extends TestService {
|
||||
*
|
||||
* private AnyValue _redkale_conf;
|
||||
* private AnyValue _redkale_conf;
|
||||
*
|
||||
* private SncpClient _redkale_client;
|
||||
* private SncpClient _redkale_client;
|
||||
*
|
||||
* private SncpServiceInfo _redkale_sncpInfo;
|
||||
* private SncpRemoteInfo _redkale_sncp;
|
||||
*
|
||||
* @Override
|
||||
* @Override
|
||||
* public void createSomeThing(TestBean bean){
|
||||
* _redkale_client.remote(_redkale_sncpInfo, 0, bean);
|
||||
* _redkale_client.remote(_redkale_sncp, 0, bean);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public String findSomeThing(){
|
||||
* return _redkale_client.remote(_redkale_sncpInfo, 1);
|
||||
* return (String)_redkale_client.remote(_redkale_sncp, 1);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public String updateSomeThing(String id){
|
||||
* return _redkale_client.remote(_redkale_sncpInfo, 2, id);
|
||||
* return (String)_redkale_client.remote(_redkale_sncp, 2, id);
|
||||
* }
|
||||
* }
|
||||
* </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) {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
||||
*
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @ResourceType(TestService.class)
|
||||
* class TestServiceImpl implements TestService {
|
||||
*
|
||||
* @Override
|
||||
* public boolean change(TestBean bean, String name, int id) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
|
||||
*
|
||||
* @Override
|
||||
* public void completed(Boolean result, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void failed(Throwable exc, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_change extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_change(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* Object rs = serviceObj.change(arg1, arg2, arg3);
|
||||
* response.finish(boolean.class, rs);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_insert extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_insert(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* BooleanHandler arg0 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.insert(arg0, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_update extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_update(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
* short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
* CompletionHandler a3 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_changeName extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_changeName(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
||||
* response.finishFuture(paramHandlerResultType, future);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </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); //不可能会发生
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
152
src/main/java/org/redkale/net/sncp/SncpRpcGroup.java
Normal file
152
src/main/java/org/redkale/net/sncp/SncpRpcGroup.java
Normal 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->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->group->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);
|
||||
}
|
||||
}
|
||||
62
src/main/java/org/redkale/net/sncp/SncpRpcGroups.java
Normal file
62
src/main/java/org/redkale/net/sncp/SncpRpcGroups.java
Normal 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->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
||||
*
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @ResourceType(TestService.class)
|
||||
* class TestServiceImpl implements TestService {
|
||||
*
|
||||
* @Override
|
||||
* public boolean change(TestBean bean, String name, int id) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void insert(BooleanHandler handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id) {
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class BooleanHandler implements CompletionHandler<Boolean, TestBean> {
|
||||
*
|
||||
* @Override
|
||||
* public void completed(Boolean result, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void failed(Throwable exc, TestBean attachment) {
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_change extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_change(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* Object rs = serviceObj.change(arg1, arg2, arg3);
|
||||
* response.finish(boolean.class, rs);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_insert extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_insert(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* BooleanHandler arg0 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[3], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[4], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.insert(arg0, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_update extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_update(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* long a1 = convert.convertFrom(paramTypes[1], in);
|
||||
* short a2 = convert.convertFrom(paramTypes[2], in);
|
||||
* CompletionHandler a3 = response.getParamAsyncHandler();
|
||||
* convert.convertFrom(CompletionHandler.class, in);
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[5], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[6], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* serviceObj.update(a1, a2, a3, arg1, arg2, arg3);
|
||||
* response.finishVoid();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class DynActionTestService_changeName extends SncpActionServlet {
|
||||
*
|
||||
* public DynActionTestService_changeName(String resourceName, Class resourceType, Service service, Uint128 serviceid, Uint128 actionid, final Method method) {
|
||||
* super(resourceName, resourceType, service, serviceid, actionid, method);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||
* Convert<Reader, Writer> convert = request.getConvert();
|
||||
* Reader in = request.getReader();
|
||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* TestService serviceObj = (TestService) service();
|
||||
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
||||
* response.finishFuture(paramHandlerResultType, future);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </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); //不可能会发生
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user