Compare commits
133 Commits
1.9.8
...
2.0.0.beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b2fd9965b | ||
|
|
0938635eb2 | ||
|
|
a4a186751e | ||
|
|
ea5169b5c5 | ||
|
|
01bd195847 | ||
|
|
a72c26a935 | ||
|
|
a9900d9bfa | ||
|
|
6896401d2d | ||
|
|
886f01c9f3 | ||
|
|
59c9251d70 | ||
|
|
fad5f010d2 | ||
|
|
737c4a92b9 | ||
|
|
d3e8675948 | ||
|
|
a4ffc7a27c | ||
|
|
91bf7b1387 | ||
|
|
1396296337 | ||
|
|
e4672355fc | ||
|
|
129ed25ca4 | ||
|
|
e6d7e5fe98 | ||
|
|
73ce5fa11f | ||
|
|
ce01c3d4ce | ||
|
|
3b3de316ea | ||
|
|
8c739ce54d | ||
|
|
0aa4d6c967 | ||
|
|
d7a3f4d87d | ||
|
|
fe9e074581 | ||
|
|
40813e8752 | ||
|
|
e90f2e4142 | ||
|
|
2a19ea709b | ||
|
|
30c9be303f | ||
|
|
e101b79472 | ||
|
|
8ad919f952 | ||
|
|
294543c46e | ||
|
|
79f8363d47 | ||
|
|
6d3553b0b5 | ||
|
|
403ab4e281 | ||
|
|
87e7c43032 | ||
|
|
a321b41699 | ||
|
|
fea34863e3 | ||
|
|
bcaf7ab73e | ||
|
|
b9d7eaee1b | ||
|
|
d605045858 | ||
|
|
cf2ab617c2 | ||
|
|
204514cb08 | ||
|
|
cfe01cca75 | ||
|
|
ac294c58ae | ||
|
|
6950eb2f30 | ||
|
|
847f81374b | ||
|
|
bb09aea8bb | ||
|
|
2e1ff333f5 | ||
|
|
c14a2b4011 | ||
|
|
d9c6c3d2d0 | ||
|
|
91d4477ed9 | ||
|
|
623c0a127e | ||
|
|
bc64666700 | ||
|
|
5c7dd7d782 | ||
|
|
e78a2da6c0 | ||
|
|
065be6f3d7 | ||
|
|
874f3330b8 | ||
|
|
684edfa10b | ||
|
|
e69a120965 | ||
|
|
4a36244294 | ||
|
|
cb444be0f7 | ||
|
|
8b5cbf186f | ||
|
|
dbc6f8a196 | ||
|
|
9b94604166 | ||
|
|
cc98a85711 | ||
|
|
6855d06f55 | ||
|
|
89d90ddf5b | ||
|
|
6280111121 | ||
|
|
231d41c15f | ||
|
|
cfca7adc66 | ||
|
|
aedd215de4 | ||
|
|
df8e839580 | ||
|
|
300441b9f7 | ||
|
|
1a5e9022ae | ||
|
|
2a3b8f87d3 | ||
|
|
b7930f1ed7 | ||
|
|
a78c2145e6 | ||
|
|
ee20a34a70 | ||
|
|
33bd80c572 | ||
|
|
031309b105 | ||
|
|
bcbd981a9b | ||
|
|
b7ce390c33 | ||
|
|
c9d099c694 | ||
|
|
fcca0329c6 | ||
|
|
c82c0bc680 | ||
|
|
2921478a0a | ||
|
|
61a5420d48 | ||
|
|
702ab6ef6e | ||
|
|
2576e71a7d | ||
|
|
0d0bd78213 | ||
|
|
8d9fa8f9cf | ||
|
|
25eaf6e353 | ||
|
|
8afcaa0b34 | ||
|
|
1824f8150c | ||
|
|
2f89778fd6 | ||
|
|
f9d250b43c | ||
|
|
3a3c09d8aa | ||
|
|
09a0d4f9e2 | ||
|
|
3bba781183 | ||
|
|
6426f8fe91 | ||
|
|
5906594148 | ||
|
|
1b188c863c | ||
|
|
087b4cb571 | ||
|
|
c9496b6231 | ||
|
|
60d95d7628 | ||
|
|
dd9e7e77b5 | ||
|
|
50c9363876 | ||
|
|
938e357745 | ||
|
|
08ee51f8ab | ||
|
|
40ae555645 | ||
|
|
33f89264a6 | ||
|
|
e4ea20cc5f | ||
|
|
045b7db1af | ||
|
|
676c1b5d21 | ||
|
|
e4319246b8 | ||
|
|
32d8515bf4 | ||
|
|
d7e7113201 | ||
|
|
9493aa43a7 | ||
|
|
d07c55b831 | ||
|
|
47dab88d72 | ||
|
|
9e553aeff6 | ||
|
|
ed8e754557 | ||
|
|
651dc3df2a | ||
|
|
84e5bc3437 | ||
|
|
64fd0176ac | ||
|
|
c1f3115d4e | ||
|
|
1c70834760 | ||
|
|
7c901731bc | ||
|
|
2b2d53e515 | ||
|
|
be051ecf45 | ||
|
|
18534eb654 |
@@ -19,8 +19,6 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
编译RedKale 1.8.x版本需要在源码工程中的编译器选项中加入: <b>-XDignore.symbol.file=true</b>
|
|
||||||
|
|
||||||
<h5>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
|
<h5>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
|
||||||
|
|
||||||
<h5>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
|
<h5>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</request>
|
</request>
|
||||||
|
|
||||||
<response>
|
<response>
|
||||||
<defcookie domain="" path=""/>
|
<defcookie domain="" path="/"/>
|
||||||
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
||||||
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
||||||
</response>
|
</response>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<persistence-unit name="user.write" transaction-type="RESOURCE_LOCAL">
|
<persistence-unit name="user.write" transaction-type="RESOURCE_LOCAL">
|
||||||
<shared-cache-mode>ALL</shared-cache-mode>
|
<shared-cache-mode>ALL</shared-cache-mode>
|
||||||
<properties>
|
<properties>
|
||||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/user?autoReconnect=true&characterEncoding=utf8"/>
|
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"/>
|
||||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||||
<property name="javax.persistence.jdbc.password" value="1234"/>
|
<property name="javax.persistence.jdbc.password" value="1234"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@@ -67,7 +67,6 @@
|
|||||||
<encoding>UTF-8</encoding>
|
<encoding>UTF-8</encoding>
|
||||||
<compilerArguments>
|
<compilerArguments>
|
||||||
<verbose />
|
<verbose />
|
||||||
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
|
|
||||||
</compilerArguments>
|
</compilerArguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
@@ -114,7 +113,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>2.10.3</version>
|
<version>3.0.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
-->
|
-->
|
||||||
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
|
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
|
||||||
<!--
|
<!--
|
||||||
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存
|
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存, 非NONE字样统一视为ALL
|
||||||
-->
|
-->
|
||||||
<property name="javax.persistence.cachemode" value="ALL"/>
|
<property name="javax.persistence.cachemode" value="ALL"/>
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ public final class ApiDocsService {
|
|||||||
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
|
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
|
||||||
out.write(json.getBytes("UTF-8"));
|
out.write(json.getBytes("UTF-8"));
|
||||||
out.close();
|
out.close();
|
||||||
File doctemplate = new File(app.getConf(), "apidoc-template.html");
|
File doctemplate = new File(app.getConfPath(), "apidoc-template.html");
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
if (doctemplate.isFile() && doctemplate.canRead()) {
|
if (doctemplate.isFile() && doctemplate.canRead()) {
|
||||||
in = new FileInputStream(doctemplate);
|
in = new FileInputStream(doctemplate);
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ public final class Application {
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------
|
||||||
//是否用于main方法运行
|
//是否用于main方法运行
|
||||||
private final boolean singletonrun;
|
final boolean singletonrun;
|
||||||
|
|
||||||
//根WatchFactory
|
//根WatchFactory
|
||||||
//private final WatchFactory watchFactory = WatchFactory.root();
|
//private final WatchFactory watchFactory = WatchFactory.root();
|
||||||
@@ -143,7 +143,7 @@ public final class Application {
|
|||||||
private final File home;
|
private final File home;
|
||||||
|
|
||||||
//配置文件目录
|
//配置文件目录
|
||||||
private final File conf;
|
private final File confPath;
|
||||||
|
|
||||||
//日志
|
//日志
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
@@ -181,9 +181,9 @@ public final class Application {
|
|||||||
this.home = root.getCanonicalFile();
|
this.home = root.getCanonicalFile();
|
||||||
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
||||||
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||||
this.conf = new File(confsubpath).getCanonicalFile();
|
this.confPath = new File(confsubpath).getCanonicalFile();
|
||||||
} else {
|
} else {
|
||||||
this.conf = new File(this.home, confsubpath).getCanonicalFile();
|
this.confPath = new File(this.home, confsubpath).getCanonicalFile();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -209,7 +209,7 @@ public final class Application {
|
|||||||
System.setProperty(RESNAME_APP_NODE, node);
|
System.setProperty(RESNAME_APP_NODE, node);
|
||||||
}
|
}
|
||||||
//以下是初始化日志配置
|
//以下是初始化日志配置
|
||||||
final File logconf = new File(conf, "logging.properties");
|
final File logconf = new File(confPath, "logging.properties");
|
||||||
if (logconf.isFile() && logconf.canRead()) {
|
if (logconf.isFile() && logconf.canRead()) {
|
||||||
try {
|
try {
|
||||||
final String rootpath = root.getCanonicalPath().replace('\\', '/');
|
final String rootpath = root.getCanonicalPath().replace('\\', '/');
|
||||||
@@ -375,8 +375,8 @@ public final class Application {
|
|||||||
return home;
|
return home;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getConf() {
|
public File getConfPath() {
|
||||||
return conf;
|
return confPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getStartTime() {
|
public long getStartTime() {
|
||||||
@@ -398,9 +398,9 @@ public final class Application {
|
|||||||
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
|
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
|
||||||
System.setProperty("convert.json.writer.buffer.defsize", "4096");
|
System.setProperty("convert.json.writer.buffer.defsize", "4096");
|
||||||
|
|
||||||
File persist = new File(this.conf, "persistence.xml");
|
File persist = new File(this.confPath, "persistence.xml");
|
||||||
final String homepath = this.home.getCanonicalPath();
|
final String homepath = this.home.getCanonicalPath();
|
||||||
final String confpath = this.conf.getCanonicalPath();
|
final String confpath = this.confPath.getCanonicalPath();
|
||||||
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
||||||
String pidstr = "";
|
String pidstr = "";
|
||||||
try { //JDK 9+
|
try { //JDK 9+
|
||||||
@@ -425,7 +425,7 @@ public final class Application {
|
|||||||
if (dfloads != null) {
|
if (dfloads != null) {
|
||||||
for (String dfload : dfloads.split(";")) {
|
for (String dfload : dfloads.split(";")) {
|
||||||
if (dfload.trim().isEmpty()) continue;
|
if (dfload.trim().isEmpty()) continue;
|
||||||
final File df = (dfload.indexOf('/') < 0) ? new File(conf, "/" + dfload) : new File(dfload);
|
final File df = (dfload.indexOf('/') < 0) ? new File(confPath, "/" + dfload) : new File(dfload);
|
||||||
if (df.isFile()) {
|
if (df.isFile()) {
|
||||||
Properties ps = new Properties();
|
Properties ps = new Properties();
|
||||||
InputStream in = new FileInputStream(df);
|
InputStream in = new FileInputStream(df);
|
||||||
@@ -467,7 +467,7 @@ public final class Application {
|
|||||||
try {
|
try {
|
||||||
Resource res = field.getAnnotation(Resource.class);
|
Resource res = field.getAnnotation(Resource.class);
|
||||||
if (res == null) return;
|
if (res == null) return;
|
||||||
if (Sncp.isRemote((Service) src)) return; //远程模式不得注入
|
if (src instanceof Service && Sncp.isRemote((Service) src)) return; //远程模式不得注入
|
||||||
Class type = field.getType();
|
Class type = field.getType();
|
||||||
if (type == Application.class) {
|
if (type == Application.class) {
|
||||||
field.set(src, application);
|
field.set(src, application);
|
||||||
@@ -559,8 +559,8 @@ public final class Application {
|
|||||||
|
|
||||||
public void restoreConfig() throws IOException {
|
public void restoreConfig() throws IOException {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
File confFile = new File(this.conf, "application.xml");
|
File confFile = new File(this.confPath, "application.xml");
|
||||||
confFile.renameTo(new File(this.conf, "application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
|
confFile.renameTo(new File(this.confPath, "application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
|
||||||
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
|
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
|
||||||
ps.append(config.toXML("application"));
|
ps.append(config.toXML("application"));
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -812,13 +812,22 @@ public final class Application {
|
|||||||
sercdl.await();
|
sercdl.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Service> T singleton(Class<T> serviceClass) throws Exception {
|
public static <T extends Service> T singleton(Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
|
||||||
return singleton("", serviceClass);
|
return singleton("", serviceClass, extServiceClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Service> T singleton(String name, Class<T> serviceClass) throws Exception {
|
public static <T extends Service> T singleton(String name, Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
|
||||||
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
|
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
|
||||||
final Application application = Application.create(true);
|
final Application application = Application.create(true);
|
||||||
|
System.setProperty("red" + "kale-singleton-serviceclass", serviceClass.getName());
|
||||||
|
if (extServiceClasses != null && extServiceClasses.length > 0) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Class clazz : extServiceClasses) {
|
||||||
|
if (sb.length() > 0) sb.append(',');
|
||||||
|
sb.append(clazz.getName());
|
||||||
|
}
|
||||||
|
System.setProperty("red" + "kale-singleton-extserviceclasses", sb.toString());
|
||||||
|
}
|
||||||
application.init();
|
application.init();
|
||||||
application.start();
|
application.start();
|
||||||
for (NodeServer server : application.servers) {
|
for (NodeServer server : application.servers) {
|
||||||
@@ -878,7 +887,7 @@ public final class Application {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdown() throws Exception {
|
public void shutdown() throws Exception {
|
||||||
for (ApplicationListener listener : this.listeners) {
|
for (ApplicationListener listener : this.listeners) {
|
||||||
try {
|
try {
|
||||||
listener.preShutdown(this);
|
listener.preShutdown(this);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.lang.reflect.Modifier;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.jar.*;
|
import java.util.jar.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import java.util.regex.*;
|
import java.util.regex.*;
|
||||||
@@ -36,6 +37,8 @@ public final class ClassFilter<T> {
|
|||||||
|
|
||||||
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
||||||
|
|
||||||
|
private Predicate<String> expectPredicate;
|
||||||
|
|
||||||
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
||||||
|
|
||||||
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
||||||
@@ -196,7 +199,7 @@ public final class ClassFilter<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
||||||
if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)的
|
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)的
|
||||||
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
||||||
} else {
|
} else {
|
||||||
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
||||||
@@ -204,7 +207,7 @@ public final class ClassFilter<T> {
|
|||||||
} catch (Throwable cfe) {
|
} catch (Throwable cfe) {
|
||||||
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
||||||
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
|
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
|
||||||
&& (!(cfe instanceof NoClassDefFoundError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) {
|
&& (!(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);
|
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,6 +350,14 @@ public final class ClassFilter<T> {
|
|||||||
this.refused = refused;
|
this.refused = refused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Predicate<String> getExpectPredicate() {
|
||||||
|
return expectPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectPredicate(Predicate<String> predicate) {
|
||||||
|
this.expectPredicate = predicate;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getPrivilegeIncludes() {
|
public Set<String> getPrivilegeIncludes() {
|
||||||
return privilegeIncludes;
|
return privilegeIncludes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
int max = 0;
|
int max = 0;
|
||||||
if (ss != null && sb != null) {
|
if (ss != null && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
if (as.getKey().length() > max) max = as.getKey().length();
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
}
|
}
|
||||||
@@ -340,7 +340,7 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
//输出信息
|
//输出信息
|
||||||
if (ss != null && !ss.isEmpty() && sb != null) {
|
if (ss != null && !ss.isEmpty() && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
int max = 0;
|
int max = 0;
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
if (as.getKey().length() > max) max = as.getKey().length();
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.lang.reflect.*;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.AbstractMap.SimpleEntry;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
@@ -153,6 +154,20 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
||||||
|
if (application.singletonrun) { //singleton模式下只加载指定的Service
|
||||||
|
final String ssc = System.getProperty("red" + "kale-singleton-serviceclass");
|
||||||
|
final String extssc = System.getProperty("red" + "kale-singleton-extserviceclasses");
|
||||||
|
if (ssc != null) {
|
||||||
|
final List<String> sscList = new ArrayList<>();
|
||||||
|
sscList.add(ssc);
|
||||||
|
if (extssc != null && !extssc.isEmpty()) {
|
||||||
|
for (String s : extssc.split(",")) {
|
||||||
|
if (!s.isEmpty()) sscList.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serviceFilter.setExpectPredicate(c -> !sscList.contains(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
||||||
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
||||||
ClassFilter otherFilter = createOtherClassFilter();
|
ClassFilter otherFilter = createOtherClassFilter();
|
||||||
@@ -161,9 +176,10 @@ public abstract class NodeServer {
|
|||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
||||||
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
||||||
loadFilter(filterFilter, otherFilter);
|
if (!application.singletonrun) { //非singleton模式下才加载Filter、Servlet
|
||||||
loadServlet(servletFilter, otherFilter);
|
loadFilter(filterFilter, otherFilter);
|
||||||
|
loadServlet(servletFilter, otherFilter);
|
||||||
|
}
|
||||||
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,19 +193,27 @@ public abstract class NodeServer {
|
|||||||
final ResourceFactory appResFactory = application.getResourceFactory();
|
final ResourceFactory appResFactory = application.getResourceFactory();
|
||||||
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
|
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
|
||||||
final AnyValue resources = application.config.getAnyValue("resources");
|
final AnyValue resources = application.config.getAnyValue("resources");
|
||||||
final Map<String, AnyValue> cacheResource = new HashMap<>();
|
final Map<String, SimpleEntry<Class, AnyValue>> cacheResource = new HashMap<>();
|
||||||
final Map<String, AnyValue> dataResources = new HashMap<>();
|
final Map<String, SimpleEntry<Class, AnyValue>> dataResources = new HashMap<>();
|
||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
||||||
try {
|
try {
|
||||||
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
||||||
if (type == DataSource.class) type = DataJdbcSource.class;
|
if (type == DataSource.class) {
|
||||||
|
type = DataMemorySource.class;
|
||||||
|
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
|
||||||
|
if (itemConf.getValue("name", "").contains(DataSources.JDBC_URL)) {
|
||||||
|
type = DataJdbcSource.class;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!Service.class.isAssignableFrom(type)) {
|
if (!Service.class.isAssignableFrom(type)) {
|
||||||
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
|
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
|
||||||
} else if (CacheSource.class.isAssignableFrom(type)) {
|
} else if (CacheSource.class.isAssignableFrom(type)) {
|
||||||
cacheResource.put(sourceConf.getValue("name", ""), sourceConf);
|
cacheResource.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
|
||||||
} else if (DataSource.class.isAssignableFrom(type)) {
|
} else if (DataSource.class.isAssignableFrom(type)) {
|
||||||
dataResources.put(sourceConf.getValue("name", ""), sourceConf);
|
dataResources.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
|
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
|
||||||
}
|
}
|
||||||
@@ -226,26 +250,31 @@ public abstract class NodeServer {
|
|||||||
try {
|
try {
|
||||||
if (field.getAnnotation(Resource.class) == null) return;
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
|
||||||
AnyValue sourceConf = dataResources.get(resourceName);
|
SimpleEntry<Class, AnyValue> resEntry = dataResources.get(resourceName);
|
||||||
|
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
|
||||||
DataSource source = null;
|
DataSource source = null;
|
||||||
boolean needinit = true;
|
boolean needinit = true;
|
||||||
if (sourceConf != null) {
|
if (sourceConf != null) {
|
||||||
final Class sourceType = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
final Class sourceType = resEntry.getKey();
|
||||||
boolean can = false;
|
if (sourceType == DataJdbcSource.class) {
|
||||||
for (Constructor cr : sourceType.getConstructors()) {
|
source = DataSources.createDataSource(resourceName, sourceConf);
|
||||||
if (cr.getParameterCount() == 0) {
|
} else {
|
||||||
can = true;
|
boolean can = false;
|
||||||
break;
|
for (Constructor cr : sourceType.getConstructors()) {
|
||||||
|
if (cr.getParameterCount() == 0) {
|
||||||
|
can = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DataSource.class.isAssignableFrom(sourceType) && can) { // 必须有空构造函数
|
||||||
|
final Service srcService = (Service) src;
|
||||||
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
|
final Set<String> groups = new HashSet<>();
|
||||||
|
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
||||||
|
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
||||||
|
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (DataSource.class.isAssignableFrom(sourceType) && can) { // 必须有空构造函数
|
|
||||||
final Service srcService = (Service) src;
|
|
||||||
SncpClient client = Sncp.getSncpClient(srcService);
|
|
||||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
|
||||||
final Set<String> groups = new HashSet<>();
|
|
||||||
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
|
||||||
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
|
||||||
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
@@ -284,6 +313,7 @@ public abstract class NodeServer {
|
|||||||
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
|
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
|
||||||
try {
|
try {
|
||||||
if (field.getAnnotation(Resource.class) == null) return;
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if (!(src instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + src);
|
||||||
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
|
||||||
final Service srcService = (Service) src;
|
final Service srcService = (Service) src;
|
||||||
SncpClient client = Sncp.getSncpClient(srcService);
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
@@ -292,8 +322,12 @@ public abstract class NodeServer {
|
|||||||
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
||||||
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
||||||
|
|
||||||
AnyValue sourceConf = cacheResource.get(resourceName);
|
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName);
|
||||||
if (sourceConf == null) sourceConf = dataResources.get(resourceName);
|
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
|
||||||
|
if (sourceConf == null) {
|
||||||
|
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
|
||||||
|
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
|
||||||
|
}
|
||||||
final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
|
final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
|
||||||
Object source = null;
|
Object source = null;
|
||||||
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
||||||
@@ -464,7 +498,7 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
//----------------- init -----------------
|
//----------------- init -----------------
|
||||||
List<Service> swlist = new ArrayList<>(localServices);
|
List<Service> swlist = new ArrayList<>(localServices);
|
||||||
Collections.sort(swlist, (o1, o2) -> {
|
swlist.sort((o1, o2) -> {
|
||||||
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
||||||
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
||||||
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
private NodeSncpServer(Application application, AnyValue serconf) {
|
private NodeSncpServer(Application application, AnyValue serconf) {
|
||||||
super(application, createServer(application, serconf));
|
super(application, createServer(application, serconf));
|
||||||
this.sncpServer = (SncpServer) this.server;
|
this.sncpServer = (SncpServer) this.server;
|
||||||
this.consumer = sncpServer == null ? null : x -> sncpServer.addSncpServlet(x);
|
this.consumer = sncpServer == null || application.singletonrun ? null : x -> sncpServer.addSncpServlet(x); //singleton模式下不生成SncpServlet
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
||||||
|
|||||||
@@ -5,7 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot.watch;
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import org.redkale.boot.*;
|
import org.redkale.boot.*;
|
||||||
import org.redkale.net.Server;
|
import org.redkale.net.Server;
|
||||||
@@ -23,18 +26,16 @@ public class ServerWatchService extends AbstractWatchService {
|
|||||||
@Comment("不存在的Server节点")
|
@Comment("不存在的Server节点")
|
||||||
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
|
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
|
||||||
|
|
||||||
|
@Comment("更改Server监听地址端口失败")
|
||||||
|
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
@RestMapping(name = "info", comment = "单个Server信息查询")
|
@RestMapping(name = "info", comment = "单个Server信息查询")
|
||||||
public RetResult info(@RestParam(name = "#port:") int port) {
|
public RetResult info(@RestParam(name = "#port:") final int port) {
|
||||||
NodeServer node = null;
|
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||||
for (NodeServer ns : application.getNodeServers()) {
|
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null);
|
||||||
if (ns.getServer().getSocketAddress().getPort() == port) {
|
|
||||||
node = ns;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
|
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
|
||||||
return new RetResult(formatToMap(node));
|
return new RetResult(formatToMap(node));
|
||||||
}
|
}
|
||||||
@@ -49,6 +50,25 @@ public class ServerWatchService extends AbstractWatchService {
|
|||||||
return new RetResult(rs);
|
return new RetResult(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "changeaddress", comment = "更改Server的监听地址和端口")
|
||||||
|
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
|
||||||
|
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
|
||||||
|
if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
|
||||||
|
if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
|
||||||
|
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||||
|
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null);
|
||||||
|
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
|
||||||
|
final Server server = node.getServer();
|
||||||
|
InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
|
||||||
|
try {
|
||||||
|
server.changeAddress(newAddr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error");
|
||||||
|
}
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Object> formatToMap(NodeServer node) {
|
private Map<String, Object> formatToMap(NodeServer node) {
|
||||||
Server server = node.getServer();
|
Server server = node.getServer();
|
||||||
Map<String, Object> rs = new LinkedHashMap<>();
|
Map<String, Object> rs = new LinkedHashMap<>();
|
||||||
|
|||||||
@@ -170,25 +170,29 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "load", auth = false, comment = "动态增加Service")
|
@RestMapping(name = "load", auth = false, comment = "动态增加Service")
|
||||||
public RetResult loadService(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
|
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
//待开发
|
//待开发
|
||||||
return RetResult.success();
|
return RetResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "reload", auth = false, comment = "重新加载Service")
|
@RestMapping(name = "reload", auth = false, comment = "重新加载Service")
|
||||||
public RetResult reloadService(String name, String type) {
|
public RetResult reloadService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
//待开发
|
//待开发
|
||||||
return RetResult.success();
|
return RetResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "stop", auth = false, comment = "动态停止Service")
|
@RestMapping(name = "stop", auth = false, comment = "动态停止Service")
|
||||||
public RetResult stopService(String name, String type) {
|
public RetResult stopService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
//待开发
|
//待开发
|
||||||
return RetResult.success();
|
return RetResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "find", auth = false, comment = "查找Service")
|
@RestMapping(name = "find", auth = false, comment = "查找Service")
|
||||||
public RetResult find(String name, String type) {
|
public RetResult find(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
//待开发
|
//待开发
|
||||||
return RetResult.success();
|
return RetResult.success();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot.watch;
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Properties;
|
import java.util.*;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import org.redkale.boot.Application;
|
import org.redkale.boot.Application;
|
||||||
import org.redkale.net.http.*;
|
import org.redkale.net.http.*;
|
||||||
@@ -16,6 +16,7 @@ import org.redkale.source.*;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* WATCH服务, 操作DataSource源
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@@ -31,13 +32,25 @@ public class SourceWatchService extends AbstractWatchService {
|
|||||||
@Comment("PoolSource调用change方法失败")
|
@Comment("PoolSource调用change方法失败")
|
||||||
public static final int RET_SOURCE_METHOD_INVOKE_NOT_EXISTS = 1605_0003;
|
public static final int RET_SOURCE_METHOD_INVOKE_NOT_EXISTS = 1605_0003;
|
||||||
|
|
||||||
|
@Resource(name = "APP_HOME")
|
||||||
|
protected File home;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
@RestMapping(name = "change", auth = false, comment = "动态更改DataSource的配置")
|
@RestMapping(name = "change", auth = false, comment = "动态更改DataSource的配置")
|
||||||
public RetResult addNode(@RestParam(name = "name", comment = "DataSource的标识") final String name,
|
public RetResult addNode(@RestParam(name = "name", comment = "DataSource的标识") final String name,
|
||||||
@RestParam(name = "properties", comment = "配置") final Properties properties) throws IOException {
|
@RestParam(name = "properties", comment = "配置") Properties properties,
|
||||||
|
@RestParam(name = "xmlpath", comment = "配置文件路径") String xmlpath) throws IOException {
|
||||||
if (name == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (name)");
|
if (name == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (name)");
|
||||||
|
if (properties == null && xmlpath != null) {
|
||||||
|
File f = new File(xmlpath);
|
||||||
|
if (!f.isFile()) f = new File(home, xmlpath);
|
||||||
|
if (!f.isFile()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found file (" + xmlpath + ")");
|
||||||
|
FileInputStream in = new FileInputStream(f);
|
||||||
|
Map<String, Properties> map = DataSources.loadPersistenceXml(in);
|
||||||
|
properties = map.get(name);
|
||||||
|
}
|
||||||
if (properties == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (properties)");
|
if (properties == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (properties)");
|
||||||
DataSource source = null;
|
DataSource source = null;
|
||||||
for (DataSource s : application.getDataSources()) {
|
for (DataSource s : application.getDataSources()) {
|
||||||
@@ -76,4 +89,34 @@ public class SourceWatchService extends AbstractWatchService {
|
|||||||
return new RetResult(RET_SOURCE_METHOD_INVOKE_NOT_EXISTS, "poolsource invoke method('change') error");
|
return new RetResult(RET_SOURCE_METHOD_INVOKE_NOT_EXISTS, "poolsource invoke method('change') error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test5", auth = false, comment = "预留")
|
||||||
|
public RetResult test5() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test6", auth = false, comment = "预留")
|
||||||
|
public RetResult test6() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/org/redkale/convert/AnyDecoder.java
Normal file
64
src/org/redkale/convert/AnyDecoder.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.convert.Reader.ValueType;
|
||||||
|
import static org.redkale.convert.Reader.ValueType.MAP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对不明类型的对象进行反序列化。 <br>
|
||||||
|
* <b>注意: 目前只支持文本格式</b> <br>
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class AnyDecoder implements Decodeable<Reader, Object> {
|
||||||
|
|
||||||
|
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
|
||||||
|
|
||||||
|
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
|
||||||
|
|
||||||
|
protected final Decodeable<Reader, String> stringDecoder;
|
||||||
|
|
||||||
|
protected final CollectionDecoder collectionDecoder;
|
||||||
|
|
||||||
|
protected final MapDecoder mapDecoder;
|
||||||
|
|
||||||
|
public AnyDecoder(final ConvertFactory factory) {
|
||||||
|
this.stringDecoder = factory.loadDecoder(String.class);
|
||||||
|
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
|
||||||
|
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertFrom(Reader in) {
|
||||||
|
ValueType vt = in.readType();
|
||||||
|
if (vt == null) return null;
|
||||||
|
switch (vt) {
|
||||||
|
case ARRAY:
|
||||||
|
return this.collectionDecoder.convertFrom(in);
|
||||||
|
case MAP:
|
||||||
|
return this.mapDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
return this.stringDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return void.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -28,9 +28,9 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
|
|
||||||
protected final Class componentClass;
|
protected final Class componentClass;
|
||||||
|
|
||||||
protected final Decodeable<Reader, T> decoder;
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
this.componentClass = (Class) this.componentType;
|
this.componentClass = (Class) this.componentType;
|
||||||
}
|
}
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@@ -66,14 +66,15 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public T[] convertFrom(Reader in, DeMember member) {
|
public T[] convertFrom(Reader in, DeMember member) {
|
||||||
int len = in.readArrayB(member, decoder);
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
contentLength = in.readMemberContentLength(member, decoder);
|
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||||
len = Reader.SIGN_NOLENGTH;
|
len = Reader.SIGN_NOLENGTH;
|
||||||
}
|
}
|
||||||
if (this.decoder == null) {
|
if (this.componentDecoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -84,7 +85,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Decodeable<Reader, T> localdecoder = this.decoder;
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
final List<T> result = new ArrayList();
|
final List<T> result = new ArrayList();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
@@ -92,7 +93,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader itemReader = getItemReader(in, member, first);
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
if (itemReader == null) break;
|
if (itemReader == null) break;
|
||||||
result.add(readMemberValue(itemReader, member, first));
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -109,17 +110,21 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T readMemberValue(Reader in, DeMember member, boolean first) {
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
return this.decoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
|
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,8 +136,8 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decodeable<Reader, T> getDecoder() {
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
return decoder;
|
return componentDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
|
|
||||||
protected final Encodeable anyEncoder;
|
protected final Encodeable anyEncoder;
|
||||||
|
|
||||||
protected final Encodeable<Writer, Object> encoder;
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
throw new ConvertException("(" + type + ") is not a array type");
|
throw new ConvertException("(" + type + ") is not a array type");
|
||||||
}
|
}
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.encoder = factory.loadEncoder(this.componentType);
|
this.componentEncoder = factory.loadEncoder(this.componentType);
|
||||||
this.anyEncoder = factory.getAnyEncoder();
|
this.anyEncoder = factory.getAnyEncoder();
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -66,11 +66,11 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (value.length == 0) {
|
if (value.length == 0) {
|
||||||
out.writeArrayB(0, encoder, value);
|
out.writeArrayB(0, componentEncoder, value);
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.encoder == null) {
|
if (this.componentEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -81,12 +81,12 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeArrayB(value.length, encoder, value) < 0) {
|
if (out.writeArrayB(value.length, componentEncoder, value) < 0) {
|
||||||
final Type comp = this.componentType;
|
final Type comp = this.componentType;
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Object v : value) {
|
for (Object v : value) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? encoder : anyEncoder), v, first);
|
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? componentEncoder : anyEncoder), v, first);
|
||||||
if (first) first = false;
|
if (first) first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.encoder + "}";
|
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -111,8 +111,8 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, Object> getEncoder() {
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
return encoder;
|
return componentEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package org.redkale.convert;
|
|||||||
import org.redkale.util.Creator;
|
import org.redkale.util.Creator;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection的反序列化操作类 <br>
|
* Collection的反序列化操作类 <br>
|
||||||
@@ -29,9 +29,9 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
|
|
||||||
protected Creator<Collection<T>> creator;
|
protected Creator<Collection<T>> creator;
|
||||||
|
|
||||||
protected final Decodeable<Reader, T> decoder;
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -43,12 +43,12 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
this.componentType = pt.getActualTypeArguments()[0];
|
this.componentType = pt.getActualTypeArguments()[0];
|
||||||
this.creator = factory.loadCreator((Class) pt.getRawType());
|
this.creator = factory.loadCreator((Class) pt.getRawType());
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} else if (factory.isReversible()) {
|
} else if (factory.isReversible()) {
|
||||||
this.componentType = Object.class;
|
this.componentType = Object.class;
|
||||||
this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class);
|
this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class);
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} else {
|
} else {
|
||||||
throw new ConvertException("CollectionDecoder not support the type (" + type + ")");
|
throw new ConvertException("CollectionDecoder not support the type (" + type + ")");
|
||||||
}
|
}
|
||||||
@@ -60,20 +60,32 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//仅供类似JsonAnyDecoder这种动态创建使用, 不得调用 factory.register
|
||||||
|
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
|
||||||
|
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
|
||||||
|
Objects.requireNonNull(componentDecoder);
|
||||||
|
this.type = type;
|
||||||
|
this.componentType = componentType;
|
||||||
|
this.creator = creator;
|
||||||
|
this.componentDecoder = componentDecoder;
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<T> convertFrom(Reader in) {
|
public Collection<T> convertFrom(Reader in) {
|
||||||
return convertFrom(in, null);
|
return convertFrom(in, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<T> convertFrom(Reader in, DeMember member) {
|
public Collection<T> convertFrom(Reader in, DeMember member) {
|
||||||
int len = in.readArrayB(member, decoder);
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
contentLength = in.readMemberContentLength(member, decoder);
|
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||||
len = Reader.SIGN_NOLENGTH;
|
len = Reader.SIGN_NOLENGTH;
|
||||||
}
|
}
|
||||||
if (this.decoder == null) {
|
if (this.componentDecoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -84,7 +96,7 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Decodeable<Reader, T> localdecoder = this.decoder;
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
final Collection<T> result = this.creator.create();
|
final Collection<T> result = this.creator.create();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
@@ -92,7 +104,7 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader itemReader = getItemReader(in, member, first);
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
if (itemReader == null) break;
|
if (itemReader == null) break;
|
||||||
result.add(readMemberValue(itemReader, member, first));
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -108,12 +120,16 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T readMemberValue(Reader in, DeMember member, boolean first) {
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
return this.decoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,8 +141,8 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decodeable<Reader, T> getDecoder() {
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
return decoder;
|
return componentDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
|
|
||||||
protected final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
protected final Encodeable<Writer, Object> encoder;
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -35,12 +35,12 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
if (t instanceof TypeVariable) {
|
if (t instanceof TypeVariable) {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.loadEncoder(t);
|
this.componentEncoder = factory.loadEncoder(t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -61,11 +61,11 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (value.isEmpty()) {
|
if (value.isEmpty()) {
|
||||||
out.writeArrayB(0, encoder, value);
|
out.writeArrayB(0, componentEncoder, value);
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.encoder == null) {
|
if (this.componentEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -76,7 +76,7 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeArrayB(value.size(), encoder, value) < 0) {
|
if (out.writeArrayB(value.size(), componentEncoder, value) < 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Object v : value) {
|
for (Object v : value) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
@@ -88,7 +88,7 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeValue(Writer out, EnMember member, Object value) {
|
protected void writeValue(Writer out, EnMember member, Object value) {
|
||||||
encoder.convertTo(out, value);
|
componentEncoder.convertTo(out, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,8 +96,11 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, Object> getEncoder() {
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
return encoder;
|
return componentEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentEncoder == null ? null : componentEncoder.getType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
|||||||
|
|
||||||
public abstract boolean isBinary();
|
public abstract boolean isBinary();
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
|
||||||
|
|
||||||
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
||||||
|
|
||||||
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
||||||
|
|||||||
@@ -89,4 +89,9 @@ public final class ConvertColumnEntry {
|
|||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,8 +91,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
|
|
||||||
this.register(Number.class, NumberSimpledCoder.instance);
|
this.register(Number.class, NumberSimpledCoder.instance);
|
||||||
this.register(String.class, StringSimpledCoder.instance);
|
this.register(String.class, StringSimpledCoder.instance);
|
||||||
|
this.register(StringConvertWrapper.class, StringConvertWrapperSimpledCoder.instance);
|
||||||
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
||||||
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
||||||
|
this.register(java.time.Duration.class, DurationSimpledCoder.instance);
|
||||||
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
|
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
|
||||||
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
|
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
|
||||||
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
||||||
@@ -219,15 +221,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvertColumnEntry findRef(AccessibleObject element) {
|
public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) {
|
||||||
if (element == null) return null;
|
if (element == null) return null;
|
||||||
ConvertColumnEntry en = this.columnEntrys.get(element);
|
ConvertColumnEntry en = this.columnEntrys.get(element);
|
||||||
Set<String> onlyColumns = null;
|
Set<String> onlyColumns = ignoreAlls.get(clazz);
|
||||||
if (element instanceof Method) {
|
|
||||||
onlyColumns = ignoreAlls.get(((Method) element).getDeclaringClass());
|
|
||||||
} else if (element instanceof Field) {
|
|
||||||
onlyColumns = ignoreAlls.get(((Field) element).getDeclaringClass());
|
|
||||||
}
|
|
||||||
if (en != null && onlyColumns == null) return en;
|
if (en != null && onlyColumns == null) return en;
|
||||||
final ConvertType ct = this.getConvertType();
|
final ConvertType ct = this.getConvertType();
|
||||||
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
|
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
|
||||||
@@ -254,8 +251,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
for (ConvertColumn ref : ccs) {
|
for (ConvertColumn ref : ccs) {
|
||||||
if (ref.type().contains(ct)) {
|
if (ref.type().contains(ct)) {
|
||||||
|
String realName = ref.name().isEmpty() ? fieldName : ref.name();
|
||||||
if (onlyColumns != null && fieldName != null) {
|
if (onlyColumns != null && fieldName != null) {
|
||||||
String realName = ref.name().isEmpty() ? fieldName : ref.name();
|
|
||||||
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
|
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
|
||||||
}
|
}
|
||||||
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
|
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
|
||||||
@@ -263,7 +260,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
entry.setIgnore(false);
|
entry.setIgnore(false);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
if (skipIgnores.isEmpty()) return entry;
|
if (skipIgnores.isEmpty()) {
|
||||||
|
if (onlyColumns != null && realName != null && onlyColumns.contains(realName)) entry.setIgnore(false);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
|
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -406,12 +406,27 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void registerIgnoreAll(final Class type, Collection<String> excludeColumns) {
|
||||||
|
Set<String> set = ignoreAlls.get(type);
|
||||||
|
if (set == null) {
|
||||||
|
ignoreAlls.put(type, new HashSet<>(excludeColumns));
|
||||||
|
} else {
|
||||||
|
set.addAll(new ArrayList(excludeColumns));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final void register(final Class type, boolean ignore, String... columns) {
|
public final void register(final Class type, boolean ignore, String... columns) {
|
||||||
for (String column : columns) {
|
for (String column : columns) {
|
||||||
register(type, column, new ConvertColumnEntry(column, ignore));
|
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void register(final Class type, boolean ignore, Collection<String> columns) {
|
||||||
|
for (String column : columns) {
|
||||||
|
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean register(final Class type, String column, String alias) {
|
public final boolean register(final Class type, String column, String alias) {
|
||||||
return register(type, column, new ConvertColumnEntry(alias));
|
return register(type, column, new ConvertColumnEntry(alias));
|
||||||
}
|
}
|
||||||
@@ -604,6 +619,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
decoder = od;
|
decoder = od;
|
||||||
} else if (!clazz.getName().startsWith("java.")
|
} else if (!clazz.getName().startsWith("java.")
|
||||||
|| java.net.HttpCookie.class == clazz
|
|| java.net.HttpCookie.class == clazz
|
||||||
|
|| java.util.AbstractMap.SimpleEntry.class == clazz
|
||||||
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
||||||
Decodeable simpleCoder = null;
|
Decodeable simpleCoder = null;
|
||||||
for (final Method method : clazz.getDeclaredMethods()) {
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
@@ -687,7 +703,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
encoder = new OptionalCoder(this, type);
|
encoder = new OptionalCoder(this, type);
|
||||||
} else if (clazz == Object.class) {
|
} else if (clazz == Object.class) {
|
||||||
return (Encodeable<W, E>) this.anyEncoder;
|
return (Encodeable<W, E>) this.anyEncoder;
|
||||||
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz) {
|
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
|
||||||
Encodeable simpleCoder = null;
|
Encodeable simpleCoder = null;
|
||||||
for (final Method method : clazz.getDeclaredMethods()) {
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
if (!Modifier.isStatic(method.getModifiers())) continue;
|
if (!Modifier.isStatic(method.getModifiers())) continue;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package org.redkale.convert;
|
|||||||
import org.redkale.util.Creator;
|
import org.redkale.util.Creator;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map的反序列化操作类 <br>
|
* Map的反序列化操作类 <br>
|
||||||
@@ -35,7 +35,7 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
|
|
||||||
protected final Decodeable<Reader, V> valueDecoder;
|
protected final Decodeable<Reader, V> valueDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -74,6 +74,20 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//仅供类似JsonAnyDecoder这种动态创建使用, 不得调用 factory.register
|
||||||
|
public MapDecoder(final ConvertFactory factory, Type type, Type keyType, Type valueType,
|
||||||
|
Creator<Map<K, V>> creator, final Decodeable<Reader, K> keyDecoder, Decodeable<Reader, V> valueDecoder) {
|
||||||
|
Objects.requireNonNull(keyDecoder);
|
||||||
|
Objects.requireNonNull(valueDecoder);
|
||||||
|
this.type = type;
|
||||||
|
this.keyType = keyType;
|
||||||
|
this.valueType = valueType;
|
||||||
|
this.creator = creator;
|
||||||
|
this.keyDecoder = keyDecoder;
|
||||||
|
this.valueDecoder = valueDecoder;
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<K, V> convertFrom(Reader in) {
|
public Map<K, V> convertFrom(Reader in) {
|
||||||
return convertFrom(in, null);
|
return convertFrom(in, null);
|
||||||
@@ -91,7 +105,8 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int len = in.readMapB(member, this.keyDecoder);
|
byte[] typevals = new byte[2];
|
||||||
|
int len = in.readMapB(member, typevals, this.keyDecoder, this.valueDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
@@ -100,22 +115,24 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
final Map<K, V> result = this.creator.create();
|
final Map<K, V> result = this.creator.create();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
|
Decodeable<Reader, K> kdecoder = getKeyDecoder(this.keyDecoder, typevals);
|
||||||
|
Decodeable<Reader, V> vdecoder = getValueDecoder(this.valueDecoder, typevals);
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
int startPosition = in.position();
|
int startPosition = in.position();
|
||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader entryReader = getEntryReader(in, member, first);
|
Reader entryReader = getEntryReader(in, member, first);
|
||||||
if (entryReader == null) break;
|
if (entryReader == null) break;
|
||||||
K key = readKeyMember(entryReader, member, first);
|
K key = readKeyMember(entryReader, member, kdecoder, first);
|
||||||
entryReader.readBlank();
|
entryReader.readBlank();
|
||||||
V value = readValueMember(entryReader, member, first);
|
V value = readValueMember(entryReader, member, vdecoder, first);
|
||||||
result.put(key, value);
|
result.put(key, value);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
K key = readKeyMember(in, member, first);
|
K key = readKeyMember(in, member, kdecoder, first);
|
||||||
in.readBlank();
|
in.readBlank();
|
||||||
V value = readValueMember(in, member, first);
|
V value = readValueMember(in, member, vdecoder, first);
|
||||||
result.put(key, value);
|
result.put(key, value);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
@@ -128,16 +145,24 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, K> getKeyDecoder(Decodeable<Reader, K> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, V> getValueDecoder(Decodeable<Reader, V> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getEntryReader(Reader in, DeMember member, boolean first) {
|
protected Reader getEntryReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected K readKeyMember(Reader in, DeMember member, boolean first) {
|
protected K readKeyMember(Reader in, DeMember member, Decodeable<Reader, K> decoder, boolean first) {
|
||||||
return keyDecoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected V readValueMember(Reader in, DeMember member, boolean first) {
|
protected V readValueMember(Reader in, DeMember member, Decodeable<Reader, V> decoder, boolean first) {
|
||||||
return valueDecoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
|
|
||||||
protected final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
protected final Encodeable<Writer, K> keyencoder;
|
protected final Encodeable<Writer, K> keyEncoder;
|
||||||
|
|
||||||
protected final Encodeable<Writer, V> valencoder;
|
protected final Encodeable<Writer, V> valueEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -37,11 +37,11 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
try {
|
try {
|
||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
|
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
|
||||||
this.keyencoder = factory.loadEncoder(pt[0]);
|
this.keyEncoder = factory.loadEncoder(pt[0]);
|
||||||
this.valencoder = factory.loadEncoder(pt[1]);
|
this.valueEncoder = factory.loadEncoder(pt[1]);
|
||||||
} else {
|
} else {
|
||||||
this.keyencoder = factory.getAnyEncoder();
|
this.keyEncoder = factory.getAnyEncoder();
|
||||||
this.valencoder = factory.getAnyEncoder();
|
this.valueEncoder = factory.getAnyEncoder();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -63,7 +63,7 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.keyencoder == null || this.valencoder == null) {
|
if (this.keyEncoder == null || this.valueEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -74,21 +74,21 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeMapB(values.size(), (Encodeable) keyencoder, (Encodeable) valencoder, value) < 0) {
|
if (out.writeMapB(values.size(), (Encodeable) keyEncoder, (Encodeable) valueEncoder, value) < 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Map.Entry<K, V> en : values.entrySet()) {
|
for (Map.Entry<K, V> en : values.entrySet()) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
writeMemberValue(out, member, en.getKey(), en.getValue(),first);
|
writeMemberValue(out, member, en.getKey(), en.getValue(), first);
|
||||||
if (first) first = false;
|
if (first) first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.writeMapE();
|
out.writeMapE();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeMemberValue(Writer out, EnMember member, K key, V value,boolean first) {
|
protected void writeMemberValue(Writer out, EnMember member, K key, V value, boolean first) {
|
||||||
keyencoder.convertTo(out, key);
|
keyEncoder.convertTo(out, key);
|
||||||
out.writeMapMark();
|
out.writeMapMark();
|
||||||
valencoder.convertTo(out, value);
|
valueEncoder.convertTo(out, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,12 +96,20 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, K> getKeyencoder() {
|
public Type getKeyType() {
|
||||||
return keyencoder;
|
return keyEncoder == null ? null : keyEncoder.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, V> getValencoder() {
|
public Type getValueType() {
|
||||||
return valencoder;
|
return valueEncoder == null ? null : valueEncoder.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Encodeable<Writer, K> getKeyEncoder() {
|
||||||
|
return keyEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Encodeable<Writer, V> getValueEncoder() {
|
||||||
|
return valueEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
|
|
||||||
protected ConvertFactory factory;
|
protected ConvertFactory factory;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -61,7 +61,10 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
public void init(final ConvertFactory factory) {
|
public void init(final ConvertFactory factory) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
try {
|
try {
|
||||||
if (type == Object.class) return;
|
if (type == Object.class) {
|
||||||
|
this.creatorConstructorMembers = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Class clazz = null;
|
Class clazz = null;
|
||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
@@ -91,7 +94,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
for (final Field field : clazz.getFields()) {
|
for (final Field field : clazz.getFields()) {
|
||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
if (factory.isConvertDisabled(field)) continue;
|
if (factory.isConvertDisabled(field)) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(clazz, field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
||||||
if (fieldCoder == null) {
|
if (fieldCoder == null) {
|
||||||
@@ -120,7 +123,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(clazz, method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
|
|
||||||
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
||||||
@@ -229,7 +232,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.creatorConstructorMembers == null) { //空构造函数
|
if (this.creatorConstructorMembers == null) { //空构造函数
|
||||||
final T result = this.creator.create();
|
final T result = this.creator == null ? null : this.creator.create();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
while (hasNext(in, first)) {
|
while (hasNext(in, first)) {
|
||||||
DeMember member = in.readFieldName(members);
|
DeMember member = in.readFieldName(members);
|
||||||
@@ -270,6 +273,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
in.readObjectE(typeClass);
|
in.readObjectE(typeClass);
|
||||||
|
if (this.creator == null) return null;
|
||||||
final T result = this.creator.create(constructorParams);
|
final T result = this.creator.create(constructorParams);
|
||||||
for (int i = 0; i < oc; i++) {
|
for (int i = 0; i < oc; i++) {
|
||||||
((Attribute) otherParams[i][0]).set(result, otherParams[i][1]);
|
((Attribute) otherParams[i][0]).set(result, otherParams[i][1]);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
|
|
||||||
protected ConvertFactory factory;
|
protected ConvertFactory factory;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
for (final Field field : clazz.getFields()) {
|
for (final Field field : clazz.getFields()) {
|
||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
if (factory.isConvertDisabled(field)) continue;
|
if (factory.isConvertDisabled(field)) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(clazz, field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
||||||
if (fieldCoder == null) {
|
if (fieldCoder == null) {
|
||||||
@@ -104,7 +104,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(clazz, method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
||||||
if (fieldCoder == null) {
|
if (fieldCoder == null) {
|
||||||
@@ -253,24 +253,24 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
|
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
|
||||||
String fieldalias;
|
String fieldalias;
|
||||||
if (field != null) { // public field
|
if (field != null) { // public field
|
||||||
ConvertColumnEntry ref = factory.findRef(field);
|
ConvertColumnEntry ref = factory.findRef(clazz, field);
|
||||||
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
|
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
|
||||||
} else if (getter != null) {
|
} else if (getter != null) {
|
||||||
ConvertColumnEntry ref = factory.findRef(getter);
|
ConvertColumnEntry ref = factory.findRef(clazz, getter);
|
||||||
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
|
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
try {
|
try {
|
||||||
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
|
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
||||||
} else { // setter != null
|
} else { // setter != null
|
||||||
ConvertColumnEntry ref = factory.findRef(setter);
|
ConvertColumnEntry ref = factory.findRef(clazz, setter);
|
||||||
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
|
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
try {
|
try {
|
||||||
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
|
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class OptionalCoder<R extends Reader, W extends Writer, T> extends Simple
|
|||||||
|
|
||||||
protected final Encodeable<Writer, T> encoder;
|
protected final Encodeable<Writer, T> encoder;
|
||||||
|
|
||||||
private boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ package org.redkale.convert;
|
|||||||
*/
|
*/
|
||||||
public abstract class Reader {
|
public abstract class Reader {
|
||||||
|
|
||||||
|
public static enum ValueType {
|
||||||
|
STRING, ARRAY, MAP;
|
||||||
|
}
|
||||||
|
|
||||||
//当前对象字段名的游标
|
//当前对象字段名的游标
|
||||||
protected int fieldIndex;
|
protected int fieldIndex;
|
||||||
|
|
||||||
@@ -73,6 +77,13 @@ public abstract class Reader {
|
|||||||
*/
|
*/
|
||||||
public abstract void readBlank();
|
public abstract void readBlank();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取下个值的类型
|
||||||
|
*
|
||||||
|
* @return ValueType
|
||||||
|
*/
|
||||||
|
public abstract ValueType readType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
||||||
*
|
*
|
||||||
@@ -95,12 +106,13 @@ public abstract class Reader {
|
|||||||
/**
|
/**
|
||||||
* 读取数组的开头并返回数组的长度
|
* 读取数组的开头并返回数组的长度
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
* @param decoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param componentDecoder Decodeable
|
||||||
*
|
*
|
||||||
* @return 返回数组的长度
|
* @return 返回数组的长度
|
||||||
*/
|
*/
|
||||||
public abstract int readArrayB(DeMember member, Decodeable decoder);
|
public abstract int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取数组的尾端
|
* 读取数组的尾端
|
||||||
@@ -111,12 +123,14 @@ public abstract class Reader {
|
|||||||
/**
|
/**
|
||||||
* 读取map的开头并返回map的size
|
* 读取map的开头并返回map的size
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
* @param keydecoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param keyDecoder Decodeable
|
||||||
|
* @param valueDecoder Decodeable
|
||||||
*
|
*
|
||||||
* @return 返回map的size
|
* @return 返回map的size
|
||||||
*/
|
*/
|
||||||
public abstract int readMapB(DeMember member, Decodeable keydecoder);
|
public abstract int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取数组的尾端
|
* 读取数组的尾端
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
|
|
||||||
protected Creator<Stream<T>> creator;
|
protected Creator<Stream<T>> creator;
|
||||||
|
|
||||||
protected final Decodeable<Reader, T> decoder;
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
this.componentType = pt.getActualTypeArguments()[0];
|
this.componentType = pt.getActualTypeArguments()[0];
|
||||||
this.creator = factory.loadCreator((Class) pt.getRawType());
|
this.creator = factory.loadCreator((Class) pt.getRawType());
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} else {
|
} else {
|
||||||
throw new ConvertException("StreamDecoder not support the type (" + type + ")");
|
throw new ConvertException("StreamDecoder not support the type (" + type + ")");
|
||||||
}
|
}
|
||||||
@@ -62,14 +62,15 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Stream<T> convertFrom(Reader in, DeMember member) {
|
public Stream<T> convertFrom(Reader in, DeMember member) {
|
||||||
int len = in.readArrayB(member, this.decoder);
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, this.componentDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
contentLength = in.readMemberContentLength(member, this.decoder);
|
contentLength = in.readMemberContentLength(member, this.componentDecoder);
|
||||||
len = Reader.SIGN_NOLENGTH;
|
len = Reader.SIGN_NOLENGTH;
|
||||||
}
|
}
|
||||||
if (this.decoder == null) {
|
if (this.componentDecoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -80,7 +81,7 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Decodeable<Reader, T> localdecoder = this.decoder;
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
final List<T> result = new ArrayList();
|
final List<T> result = new ArrayList();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
@@ -88,7 +89,7 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader itemReader = getItemReader(in, member, first);
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
if (itemReader == null) break;
|
if (itemReader == null) break;
|
||||||
result.add(readMemberValue(itemReader, member, first));
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -104,12 +105,16 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T readMemberValue(Reader in, DeMember member, boolean first) {
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
return this.decoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -121,8 +126,8 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decodeable<Reader, T> getDecoder() {
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
return decoder;
|
return componentDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
|
|
||||||
protected final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
protected final Encodeable<Writer, Object> encoder;
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -35,12 +35,12 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
if (t instanceof TypeVariable) {
|
if (t instanceof TypeVariable) {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.loadEncoder(t);
|
this.componentEncoder = factory.loadEncoder(t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -62,11 +62,11 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
}
|
}
|
||||||
Object[] array = value.toArray();
|
Object[] array = value.toArray();
|
||||||
if (array.length == 0) {
|
if (array.length == 0) {
|
||||||
out.writeArrayB(0, encoder, array);
|
out.writeArrayB(0, componentEncoder, array);
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.encoder == null) {
|
if (this.componentEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -77,7 +77,7 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeArrayB(array.length, encoder, array) < 0) {
|
if (out.writeArrayB(array.length, componentEncoder, array) < 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Object v : array) {
|
for (Object v : array) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
@@ -89,7 +89,7 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
|
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
|
||||||
encoder.convertTo(out, value);
|
componentEncoder.convertTo(out, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -97,8 +97,11 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, Object> getEncoder() {
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
return encoder;
|
return componentEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentEncoder == null ? null : componentEncoder.getType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
63
src/org/redkale/convert/StringConvertWrapper.java
Normal file
63
src/org/redkale/convert/StringConvertWrapper.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert;
|
||||||
|
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列化去掉引号的String对象。
|
||||||
|
* <blockquote><pre>
|
||||||
|
* 场景: JavaBean bean = ... ;
|
||||||
|
* Map map = new HashMap();
|
||||||
|
* map.put("bean", a);
|
||||||
|
* records.add(map);
|
||||||
|
* records需要在后期序列化写入库。 但是在这期间bean的内部字段值可能就变化了,会导致入库时并不是records.add的快照信息。
|
||||||
|
* 所以需要使用StringConvertWrapper:
|
||||||
|
* Map map = new HashMap();
|
||||||
|
* map.put("bean", new StringConvertWrapper(bean.toString()));
|
||||||
|
* records.add(map);
|
||||||
|
* 这样既可以保持快照又不会在bean的值上面多一层引号。
|
||||||
|
* </pre></blockquote>
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class StringConvertWrapper {
|
||||||
|
|
||||||
|
protected String value;
|
||||||
|
|
||||||
|
public StringConvertWrapper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringConvertWrapper(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringConvertWrapper create(Object value) {
|
||||||
|
return create(JsonConvert.root(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringConvertWrapper create(TextConvert convert, Object value) {
|
||||||
|
if (value == null) return new StringConvertWrapper(null);
|
||||||
|
if (value instanceof String) return new StringConvertWrapper((String) value);
|
||||||
|
return new StringConvertWrapper(convert.convertTo(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -129,13 +129,13 @@ public abstract class Writer {
|
|||||||
/**
|
/**
|
||||||
* 输出一个数组前的操作
|
* 输出一个数组前的操作
|
||||||
*
|
*
|
||||||
* @param size 数组长度
|
* @param size 数组长度
|
||||||
* @param encoder Encodeable
|
* @param componentEncoder Encodeable
|
||||||
* @param obj 对象
|
* @param obj 对象, 不一定是数组、Collection对象,也可能是伪Collection对象
|
||||||
*
|
*
|
||||||
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
||||||
*/
|
*/
|
||||||
public abstract int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj);
|
public abstract int writeArrayB(int size, Encodeable<Writer, Object> componentEncoder, Object obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出数组元素间的间隔符
|
* 输出数组元素间的间隔符
|
||||||
@@ -155,7 +155,7 @@ public abstract class Writer {
|
|||||||
* @param size map大小
|
* @param size map大小
|
||||||
* @param keyEncoder Encodeable
|
* @param keyEncoder Encodeable
|
||||||
* @param valueEncoder Encodeable
|
* @param valueEncoder Encodeable
|
||||||
* @param obj 对象
|
* @param obj 对象, 不一定是Map对象,也可能是伪Map对象
|
||||||
*
|
*
|
||||||
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
||||||
*/
|
*/
|
||||||
@@ -256,4 +256,11 @@ public abstract class Writer {
|
|||||||
* @param value String值
|
* @param value String值
|
||||||
*/
|
*/
|
||||||
public abstract void writeString(String value);
|
public abstract void writeString(String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入一个StringConvertWrapper值
|
||||||
|
*
|
||||||
|
* @param value StringConvertWrapper值
|
||||||
|
*/
|
||||||
|
public abstract void writeWrapper(StringConvertWrapper value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.redkale.convert.bson;
|
|||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import static org.redkale.convert.Reader.SIGN_NULL;
|
import static org.redkale.convert.Reader.SIGN_NULL;
|
||||||
|
import org.redkale.convert.ext.ByteSimpledCoder;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,18 +49,38 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position()));
|
return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断下一个非空白字节是否为[
|
|
||||||
*
|
|
||||||
* @param member DeMember
|
|
||||||
* @param decoder Decodeable
|
|
||||||
* @return 数组长度或 SIGN_NULL
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public final int readArrayB(DeMember member, Decodeable decoder) {
|
public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) {
|
||||||
short bt = readShort();
|
short bt = readShort();
|
||||||
if (bt == Reader.SIGN_NULL) return bt;
|
if (bt == Reader.SIGN_NULL) return bt;
|
||||||
short lt = readShort();
|
short lt = readShort();
|
||||||
|
byte kt = readByte();
|
||||||
|
byte vt = readByte();
|
||||||
|
if (typevals != null) {
|
||||||
|
typevals[0] = kt;
|
||||||
|
typevals[1] = vt;
|
||||||
|
}
|
||||||
|
return (bt & 0xffff) << 16 | (lt & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断下一个非空白字节是否为[
|
||||||
|
*
|
||||||
|
* @param member DeMember
|
||||||
|
* @param typevals byte[]
|
||||||
|
* @param componentDecoder Decodeable
|
||||||
|
*
|
||||||
|
* @return 数组长度或 SIGN_NULL
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) {
|
||||||
|
short bt = readShort();
|
||||||
|
if (bt == Reader.SIGN_NULL) return bt;
|
||||||
|
short lt = readShort();
|
||||||
|
if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) {
|
||||||
|
byte comval = readByte();
|
||||||
|
if (typevals != null) typevals[0] = comval;
|
||||||
|
}
|
||||||
return (bt & 0xffff) << 16 | (lt & 0xffff);
|
return (bt & 0xffff) << 16 | (lt & 0xffff);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
|||||||
@@ -6,8 +6,12 @@
|
|||||||
package org.redkale.convert.bson;
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.util.AnyValue;
|
import org.redkale.convert.ext.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BSON的ConvertFactory
|
* BSON的ConvertFactory
|
||||||
@@ -26,6 +30,16 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
static final Encodeable objectEncoder = instance.loadEncoder(Object.class);
|
static final Encodeable objectEncoder = instance.loadEncoder(Object.class);
|
||||||
|
|
||||||
|
static final Decodeable skipArrayDecoder = new SkipArrayDecoder(instance, Object[].class);
|
||||||
|
|
||||||
|
static final Decodeable skipCollectionDecoder = new SkipCollectionDecoder(instance, new TypeToken<Collection<Object>>() {
|
||||||
|
}.getType());
|
||||||
|
|
||||||
|
static final Decodeable skipStreamDecoder = new SkipStreamDecoder(instance, new TypeToken<Stream<Object>>() {
|
||||||
|
}.getType());
|
||||||
|
|
||||||
|
static final Decodeable skipMapDecoder = new SkipMapDecoder(instance, Map.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
instance.register(Serializable.class, objectDecoder);
|
instance.register(Serializable.class, objectDecoder);
|
||||||
instance.register(Serializable.class, objectEncoder);
|
instance.register(Serializable.class, objectEncoder);
|
||||||
@@ -89,4 +103,110 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static byte typeEnum(final Type type) {
|
||||||
|
return typeEnum(TypeToken.typeToClass(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static byte typeEnum(final Class type) {
|
||||||
|
Objects.requireNonNull(type);
|
||||||
|
byte typeval = 127; //字段的类型值
|
||||||
|
if (type == boolean.class || type == Boolean.class) {
|
||||||
|
typeval = 11;
|
||||||
|
} else if (type == byte.class || type == Byte.class) {
|
||||||
|
typeval = 12;
|
||||||
|
} else if (type == short.class || type == Short.class) {
|
||||||
|
typeval = 13;
|
||||||
|
} else if (type == char.class || type == Character.class) {
|
||||||
|
typeval = 14;
|
||||||
|
} else if (type == int.class || type == Integer.class) {
|
||||||
|
typeval = 15;
|
||||||
|
} else if (type == long.class || type == Long.class) {
|
||||||
|
typeval = 16;
|
||||||
|
} else if (type == float.class || type == Float.class) {
|
||||||
|
typeval = 17;
|
||||||
|
} else if (type == double.class || type == Double.class) {
|
||||||
|
typeval = 18;
|
||||||
|
} else if (type == String.class) {
|
||||||
|
typeval = 19;
|
||||||
|
} else if (type == boolean[].class || type == Boolean[].class) {
|
||||||
|
typeval = 21;
|
||||||
|
} else if (type == byte[].class || type == Byte[].class) {
|
||||||
|
typeval = 22;
|
||||||
|
} else if (type == short[].class || type == Short[].class) {
|
||||||
|
typeval = 23;
|
||||||
|
} else if (type == char[].class || type == Character[].class) {
|
||||||
|
typeval = 24;
|
||||||
|
} else if (type == int[].class || type == Integer[].class) {
|
||||||
|
typeval = 25;
|
||||||
|
} else if (type == long[].class || type == Long[].class) {
|
||||||
|
typeval = 26;
|
||||||
|
} else if (type == float[].class || type == Float[].class) {
|
||||||
|
typeval = 27;
|
||||||
|
} else if (type == double[].class || type == Double[].class) {
|
||||||
|
typeval = 28;
|
||||||
|
} else if (type == String[].class) {
|
||||||
|
typeval = 29;
|
||||||
|
} else if (type.isArray()) {
|
||||||
|
typeval = 81;
|
||||||
|
} else if (Collection.class.isAssignableFrom(type)) {
|
||||||
|
typeval = 82;
|
||||||
|
} else if (Stream.class.isAssignableFrom(type)) {
|
||||||
|
typeval = 83;
|
||||||
|
} else if (Map.class.isAssignableFrom(type)) {
|
||||||
|
typeval = 84;
|
||||||
|
}
|
||||||
|
return typeval;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Decodeable typeEnum(final byte typeval) {
|
||||||
|
switch (typeval) {
|
||||||
|
case 11:
|
||||||
|
return BoolSimpledCoder.instance;
|
||||||
|
case 12:
|
||||||
|
return ByteSimpledCoder.instance;
|
||||||
|
case 13:
|
||||||
|
return ShortSimpledCoder.instance;
|
||||||
|
case 14:
|
||||||
|
return CharSimpledCoder.instance;
|
||||||
|
case 15:
|
||||||
|
return IntSimpledCoder.instance;
|
||||||
|
case 16:
|
||||||
|
return LongSimpledCoder.instance;
|
||||||
|
case 17:
|
||||||
|
return FloatSimpledCoder.instance;
|
||||||
|
case 18:
|
||||||
|
return DoubleSimpledCoder.instance;
|
||||||
|
case 19:
|
||||||
|
return StringSimpledCoder.instance;
|
||||||
|
case 21:
|
||||||
|
return BoolArraySimpledCoder.instance;
|
||||||
|
case 22:
|
||||||
|
return ByteArraySimpledCoder.instance;
|
||||||
|
case 23:
|
||||||
|
return ShortArraySimpledCoder.instance;
|
||||||
|
case 24:
|
||||||
|
return CharArraySimpledCoder.instance;
|
||||||
|
case 25:
|
||||||
|
return IntArraySimpledCoder.instance;
|
||||||
|
case 26:
|
||||||
|
return LongArraySimpledCoder.instance;
|
||||||
|
case 27:
|
||||||
|
return FloatArraySimpledCoder.instance;
|
||||||
|
case 28:
|
||||||
|
return DoubleArraySimpledCoder.instance;
|
||||||
|
case 29:
|
||||||
|
return StringArraySimpledCoder.instance;
|
||||||
|
case 81:
|
||||||
|
return skipArrayDecoder;
|
||||||
|
case 82:
|
||||||
|
return skipCollectionDecoder;
|
||||||
|
case 83:
|
||||||
|
return skipStreamDecoder;
|
||||||
|
case 84:
|
||||||
|
return skipMapDecoder;
|
||||||
|
case 127:
|
||||||
|
return BsonFactory.objectDecoder;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,53 +93,27 @@ public class BsonReader extends Reader {
|
|||||||
final byte val = this.typeval;
|
final byte val = this.typeval;
|
||||||
this.typeval = 0;
|
this.typeval = 0;
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1: readBoolean();
|
case 11: readBoolean();
|
||||||
break;
|
break;
|
||||||
case 2: readByte();
|
case 12: readByte();
|
||||||
break;
|
break;
|
||||||
case 3: readShort();
|
case 13: readShort();
|
||||||
break;
|
break;
|
||||||
case 4: readChar();
|
case 14: readChar();
|
||||||
break;
|
break;
|
||||||
case 5: readInt();
|
case 15: readInt();
|
||||||
break;
|
break;
|
||||||
case 6: readLong();
|
case 16: readLong();
|
||||||
break;
|
break;
|
||||||
case 7: readFloat();
|
case 17: readFloat();
|
||||||
break;
|
break;
|
||||||
case 8: readDouble();
|
case 18: readDouble();
|
||||||
break;
|
break;
|
||||||
case 9: readString();
|
case 19: readString();
|
||||||
break;
|
break;
|
||||||
case 101:
|
default:
|
||||||
BoolArraySimpledCoder.instance.convertFrom(this);
|
Decodeable decoder = BsonFactory.typeEnum(val);
|
||||||
break;
|
if (decoder != null) decoder.convertFrom(this);
|
||||||
case 102:
|
|
||||||
ByteArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 103:
|
|
||||||
ShortArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 104:
|
|
||||||
CharArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 105:
|
|
||||||
IntArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 106:
|
|
||||||
LongArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 107:
|
|
||||||
FloatArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 108:
|
|
||||||
DoubleArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 109:
|
|
||||||
StringArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 127:
|
|
||||||
BsonFactory.objectDecoder.convertFrom(this);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,8 +145,17 @@ public class BsonReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int readMapB(DeMember member, Decodeable keydecoder) {
|
public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) {
|
||||||
return readArrayB(member, keydecoder);
|
short bt = readShort();
|
||||||
|
if (bt == Reader.SIGN_NULL) return bt;
|
||||||
|
int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
||||||
|
byte kt = readByte();
|
||||||
|
byte vt = readByte();
|
||||||
|
if (typevals != null) {
|
||||||
|
typevals[0] = kt;
|
||||||
|
typevals[1] = vt;
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,10 +168,15 @@ public class BsonReader extends Reader {
|
|||||||
* @return 数组长度或SIGN_NULL
|
* @return 数组长度或SIGN_NULL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int readArrayB(DeMember member, Decodeable decoder) {
|
public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { //componentDecoder可能为null
|
||||||
short bt = readShort();
|
short bt = readShort();
|
||||||
if (bt == Reader.SIGN_NULL) return bt;
|
if (bt == Reader.SIGN_NULL) return bt;
|
||||||
return (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
||||||
|
if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) {
|
||||||
|
byte comval = readByte();
|
||||||
|
if (typevals != null) typevals[0] = comval;
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,7 +251,7 @@ public class BsonReader extends Reader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final byte[] readByteArray() {
|
public final byte[] readByteArray() {
|
||||||
int len = readArrayB(null, null);
|
int len = readArrayB(null, null, null);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
@@ -358,4 +346,9 @@ public class BsonReader extends Reader {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueType readType() {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package org.redkale.convert.bson;
|
|||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.convert.ext.ByteSimpledCoder;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,46 +202,7 @@ public class BsonWriter extends Writer {
|
|||||||
Attribute attribute = member.getAttribute();
|
Attribute attribute = member.getAttribute();
|
||||||
writeByte(BsonReader.SIGN_HASNEXT);
|
writeByte(BsonReader.SIGN_HASNEXT);
|
||||||
writeSmallString(attribute.field());
|
writeSmallString(attribute.field());
|
||||||
byte typeval = 127; //字段的类型值
|
writeByte(BsonFactory.typeEnum(attribute.type()));
|
||||||
final Class type = attribute.type();
|
|
||||||
if (type == boolean.class || type == Boolean.class) {
|
|
||||||
typeval = 1;
|
|
||||||
} else if (type == byte.class || type == Byte.class) {
|
|
||||||
typeval = 2;
|
|
||||||
} else if (type == short.class || type == Short.class) {
|
|
||||||
typeval = 3;
|
|
||||||
} else if (type == char.class || type == Character.class) {
|
|
||||||
typeval = 4;
|
|
||||||
} else if (type == int.class || type == Integer.class) {
|
|
||||||
typeval = 5;
|
|
||||||
} else if (type == long.class || type == Long.class) {
|
|
||||||
typeval = 6;
|
|
||||||
} else if (type == float.class || type == Float.class) {
|
|
||||||
typeval = 7;
|
|
||||||
} else if (type == double.class || type == Double.class) {
|
|
||||||
typeval = 8;
|
|
||||||
} else if (type == String.class) {
|
|
||||||
typeval = 9;
|
|
||||||
} else if (type == boolean[].class || type == Boolean[].class) {
|
|
||||||
typeval = 101;
|
|
||||||
} else if (type == byte[].class || type == Byte[].class) {
|
|
||||||
typeval = 102;
|
|
||||||
} else if (type == short[].class || type == Short[].class) {
|
|
||||||
typeval = 103;
|
|
||||||
} else if (type == char[].class || type == Character[].class) {
|
|
||||||
typeval = 104;
|
|
||||||
} else if (type == int[].class || type == Integer[].class) {
|
|
||||||
typeval = 105;
|
|
||||||
} else if (type == long[].class || type == Long[].class) {
|
|
||||||
typeval = 106;
|
|
||||||
} else if (type == float[].class || type == Float[].class) {
|
|
||||||
typeval = 107;
|
|
||||||
} else if (type == double[].class || type == Double[].class) {
|
|
||||||
typeval = 108;
|
|
||||||
} else if (type == String[].class) {
|
|
||||||
typeval = 109;
|
|
||||||
}
|
|
||||||
writeByte(typeval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -279,14 +241,22 @@ public class BsonWriter extends Writer {
|
|||||||
writeTo(bytes);
|
writeTo(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeWrapper(StringConvertWrapper value) {
|
||||||
|
this.writeString(value == null ? null : value.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeNull() {
|
public final void writeNull() {
|
||||||
writeShort(Reader.SIGN_NULL);
|
writeShort(Reader.SIGN_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
|
public final int writeArrayB(int size, Encodeable<Writer, Object> componentEncoder, Object obj) {
|
||||||
writeInt(size);
|
writeInt(size);
|
||||||
|
if (componentEncoder != null && componentEncoder != ByteSimpledCoder.instance) {
|
||||||
|
writeByte(BsonFactory.typeEnum(componentEncoder.getType()));
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +270,9 @@ public class BsonWriter extends Writer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
|
public int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
|
||||||
writeArrayB(size, valueEncoder, obj);
|
writeInt(size);
|
||||||
|
writeByte(BsonFactory.typeEnum(keyEncoder.getType()));
|
||||||
|
writeByte(BsonFactory.typeEnum(valueEncoder.getType()));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
33
src/org/redkale/convert/bson/SkipArrayDecoder.java
Normal file
33
src/org/redkale/convert/bson/SkipArrayDecoder.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数组的反序列化操作类 <br>
|
||||||
|
* 对象数组的反序列化,不包含int[]、long[]这样的primitive class数组。 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的数组元素类型
|
||||||
|
*/
|
||||||
|
public class SkipArrayDecoder<T> extends ArrayDecoder<T> {
|
||||||
|
|
||||||
|
public SkipArrayDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/org/redkale/convert/bson/SkipCollectionDecoder.java
Normal file
32
src/org/redkale/convert/bson/SkipCollectionDecoder.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection的反序列化操作类 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的集合元素类型
|
||||||
|
*/
|
||||||
|
public class SkipCollectionDecoder<T> extends CollectionDecoder<T> {
|
||||||
|
|
||||||
|
public SkipCollectionDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/org/redkale/convert/bson/SkipMapDecoder.java
Normal file
38
src/org/redkale/convert/bson/SkipMapDecoder.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map的反序列化操作类 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <K> Map key的数据类型
|
||||||
|
* @param <V> Map value的数据类型
|
||||||
|
*/
|
||||||
|
public class SkipMapDecoder<K, V> extends MapDecoder<K, V> {
|
||||||
|
|
||||||
|
public SkipMapDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, K> getKeyDecoder(Decodeable<Reader, K> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, V> getValueDecoder(Decodeable<Reader, V> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[1]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/org/redkale/convert/bson/SkipStreamDecoder.java
Normal file
32
src/org/redkale/convert/bson/SkipStreamDecoder.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream的反序列化操作类 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的集合元素类型
|
||||||
|
*/
|
||||||
|
public class SkipStreamDecoder<T> extends StreamDecoder<T> {
|
||||||
|
|
||||||
|
public SkipStreamDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ public final class BoolArraySimpledCoder<R extends Reader, W extends Writer> ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean[] convertFrom(R in) {
|
public boolean[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, BoolSimpledCoder.instance);
|
int len = in.readArrayB(null, null, BoolSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class ByteBufferSimpledCoder<R extends Reader, W extends Writer> ex
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer convertFrom(R in) {
|
public ByteBuffer convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, ByteSimpledCoder.instance);
|
int len = in.readArrayB(null, null, ByteSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public final class CharArraySimpledCoder<R extends Reader, W extends Writer> ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char[] convertFrom(R in) {
|
public char[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, CharSimpledCoder.instance);
|
int len = in.readArrayB(null, null, CharSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> e
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double[] convertFrom(R in) {
|
public double[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, DoubleSimpledCoder.instance);
|
int len = in.readArrayB(null, null, DoubleSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
41
src/org/redkale/convert/ext/DurationSimpledCoder.java
Normal file
41
src/org/redkale/convert/ext/DurationSimpledCoder.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert.ext;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public class DurationSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Duration> {
|
||||||
|
|
||||||
|
public static final DurationSimpledCoder instance = new DurationSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, Duration value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
out.writeLong(value.toNanos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Duration convertFrom(R in) {
|
||||||
|
String value = in.readSmallString();
|
||||||
|
if (value == null) return null;
|
||||||
|
return Duration.ofNanos(Long.parseLong(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ public final class FloatArraySimpledCoder<R extends Reader, W extends Writer> ex
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float[] convertFrom(R in) {
|
public float[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, FloatSimpledCoder.instance);
|
int len = in.readArrayB(null, null, FloatSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class IntArraySimpledCoder<R extends Reader, W extends Writer> exte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] convertFrom(R in) {
|
public int[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, IntSimpledCoder.instance);
|
int len = in.readArrayB(null, null, IntSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class LongArraySimpledCoder<R extends Reader, W extends Writer> ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long[] convertFrom(R in) {
|
public long[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, LongSimpledCoder.instance);
|
int len = in.readArrayB(null, null, LongSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public final class ShortArraySimpledCoder<R extends Reader, W extends Writer> ex
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short[] convertFrom(R in) {
|
public short[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, ShortSimpledCoder.instance);
|
int len = in.readArrayB(null, null, ShortSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public final class StringArraySimpledCoder<R extends Reader, W extends Writer> e
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String[] convertFrom(R in, DeMember member) {
|
public String[] convertFrom(R in, DeMember member) {
|
||||||
int len = in.readArrayB(member, StringSimpledCoder.instance);
|
int len = in.readArrayB(member, null, StringSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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.convert.ext;
|
||||||
|
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public final class StringConvertWrapperSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringConvertWrapper> {
|
||||||
|
|
||||||
|
public static final StringConvertWrapperSimpledCoder instance = new StringConvertWrapperSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, StringConvertWrapper value) {
|
||||||
|
out.writeWrapper(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringConvertWrapper convertFrom(R in) {
|
||||||
|
return new StringConvertWrapper(in.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -139,13 +139,14 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
/**
|
/**
|
||||||
* 判断下一个非空白字符是否为[
|
* 判断下一个非空白字符是否为[
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
* @param decoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param decoder Decodeable
|
||||||
*
|
*
|
||||||
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final int readArrayB(DeMember member, Decodeable decoder) {
|
public final int readArrayB(DeMember member, byte[] typevals, Decodeable decoder) {
|
||||||
char ch = nextGoodChar();
|
char ch = nextGoodChar();
|
||||||
if (ch == '[' || ch == '{') return SIGN_NOLENGTH;
|
if (ch == '[' || ch == '{') return SIGN_NOLENGTH;
|
||||||
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL;
|
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL;
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertFrom -----------------------------------------------------------
|
//------------------------------ convertFrom -----------------------------------------------------------
|
||||||
|
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
||||||
|
if (bytes == null) return null;
|
||||||
|
return convertFrom(type, new String(bytes, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
public <T> T convertFrom(final Type type, final String text) {
|
public <T> T convertFrom(final Type type, final String text) {
|
||||||
if (text == null) return null;
|
if (text == null) return null;
|
||||||
return convertFrom(type, Utility.charArray(text));
|
return convertFrom(type, Utility.charArray(text));
|
||||||
@@ -128,6 +133,52 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final String text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
return (V) convertFrom(Utility.charArray(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final char[] text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
return (V) convertFrom(text, 0, text.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final char[] text, final int start, final int len) {
|
||||||
|
if (text == null) return null;
|
||||||
|
final JsonReader in = readerPool.get();
|
||||||
|
in.setText(text, start, len);
|
||||||
|
Object rs = new AnyDecoder(factory).convertFrom(in);
|
||||||
|
readerPool.accept(in);
|
||||||
|
return (V) rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final InputStream in) {
|
||||||
|
if (in == null) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonStreamReader(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final ByteBuffer... buffers) {
|
||||||
|
if (buffers == null || buffers.length == 0) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final ConvertMask mask, final ByteBuffer... buffers) {
|
||||||
|
if (buffers == null || buffers.length == 0) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader(mask, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final JsonReader reader) {
|
||||||
|
if (reader == null) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(reader);
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ convertTo -----------------------------------------------------------
|
//------------------------------ convertTo -----------------------------------------------------------
|
||||||
@Override
|
@Override
|
||||||
public String convertTo(final Object value) {
|
public String convertTo(final Object value) {
|
||||||
|
|||||||
@@ -158,6 +158,21 @@ public class JsonReader extends Reader {
|
|||||||
this.position--;
|
this.position--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ValueType readType() {
|
||||||
|
char ch = nextGoodChar();
|
||||||
|
if (ch == '{') {
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.MAP;
|
||||||
|
}
|
||||||
|
if (ch == '[') {
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.ARRAY;
|
||||||
|
}
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断下一个非空白字符是否为{
|
* 判断下一个非空白字符是否为{
|
||||||
*
|
*
|
||||||
@@ -168,6 +183,7 @@ public class JsonReader extends Reader {
|
|||||||
@Override
|
@Override
|
||||||
public String readObjectB(final Class clazz) {
|
public String readObjectB(final Class clazz) {
|
||||||
this.fieldIndex = 0; //必须要重置为0
|
this.fieldIndex = 0; //必须要重置为0
|
||||||
|
if (this.text.length == 0) return null;
|
||||||
char ch = this.text[++this.position];
|
char ch = this.text[++this.position];
|
||||||
if (ch == '{') return "";
|
if (ch == '{') return "";
|
||||||
if (ch <= ' ') {
|
if (ch <= ' ') {
|
||||||
@@ -189,14 +205,16 @@ public class JsonReader extends Reader {
|
|||||||
/**
|
/**
|
||||||
* 判断下一个非空白字符是否为{
|
* 判断下一个非空白字符是否为{
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
* @param keydecoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param keyDecoder Decodeable
|
||||||
|
* @param valuedecoder Decodeable
|
||||||
*
|
*
|
||||||
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final int readMapB(DeMember member, Decodeable keydecoder) {
|
public final int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valuedecoder) {
|
||||||
return readArrayB(member, keydecoder);
|
return readArrayB(member, typevals, keyDecoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -206,13 +224,15 @@ public class JsonReader extends Reader {
|
|||||||
/**
|
/**
|
||||||
* 判断下一个非空白字符是否为[
|
* 判断下一个非空白字符是否为[
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
* @param decoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param componentDecoder Decodeable
|
||||||
*
|
*
|
||||||
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int readArrayB(DeMember member, Decodeable decoder) {
|
public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) {
|
||||||
|
if (this.text.length == 0) return SIGN_NULL;
|
||||||
char ch = this.text[++this.position];
|
char ch = this.text[++this.position];
|
||||||
if (ch == '[') return SIGN_NOLENGTH;
|
if (ch == '[') return SIGN_NOLENGTH;
|
||||||
if (ch == '{') return SIGN_NOLENGTH;
|
if (ch == '{') return SIGN_NOLENGTH;
|
||||||
@@ -333,7 +353,7 @@ public class JsonReader extends Reader {
|
|||||||
}
|
}
|
||||||
this.position = currpos - 1;
|
this.position = currpos - 1;
|
||||||
if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null;
|
if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null;
|
||||||
return new String(text0, start, len);
|
return new String(text0, start, len == eof ? (len + 1) : len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +494,7 @@ public class JsonReader extends Reader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final byte[] readByteArray() {
|
public final byte[] readByteArray() {
|
||||||
int len = readArrayB(null, null);
|
int len = readArrayB(null, null, null);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -319,6 +319,11 @@ public class JsonWriter extends Writer {
|
|||||||
writeTo(false, String.valueOf(value));
|
writeTo(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeWrapper(StringConvertWrapper value) {
|
||||||
|
writeTo(false, String.valueOf(value));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean needWriteClassName() {
|
public final boolean needWriteClassName() {
|
||||||
return false;
|
return false;
|
||||||
@@ -346,7 +351,7 @@ public class JsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
|
public final int writeArrayB(int size, Encodeable<Writer, Object> componentEncoder, Object obj) {
|
||||||
writeTo('[');
|
writeTo('[');
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ package org.redkale.net;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -22,7 +23,7 @@ import javax.net.ssl.SSLContext;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCloseable {
|
public abstract class AsyncConnection implements ReadableByteChannel, WritableByteChannel, AutoCloseable {
|
||||||
|
|
||||||
protected SSLContext sslContext;
|
protected SSLContext sslContext;
|
||||||
|
|
||||||
@@ -34,6 +35,12 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
protected volatile long writetime;
|
protected volatile long writetime;
|
||||||
|
|
||||||
|
protected final Supplier<ByteBuffer> bufferSupplier;
|
||||||
|
|
||||||
|
protected final Consumer<ByteBuffer> bufferConsumer;
|
||||||
|
|
||||||
|
protected ByteBuffer readBuffer;
|
||||||
|
|
||||||
//在线数
|
//在线数
|
||||||
protected AtomicLong livingCounter;
|
protected AtomicLong livingCounter;
|
||||||
|
|
||||||
@@ -45,6 +52,22 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
//关联的事件数, 小于1表示没有事件
|
//关联的事件数, 小于1表示没有事件
|
||||||
protected final AtomicInteger eventing = new AtomicInteger();
|
protected final AtomicInteger eventing = new AtomicInteger();
|
||||||
|
|
||||||
|
protected AsyncConnection(Context context) {
|
||||||
|
this(context.getBufferSupplier(), context.getBufferConsumer(), context.getSSLContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AsyncConnection(ObjectPool<ByteBuffer> bufferPool, SSLContext sslContext) {
|
||||||
|
this(bufferPool, bufferPool, sslContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer, SSLContext sslContext) {
|
||||||
|
Objects.requireNonNull(bufferSupplier);
|
||||||
|
Objects.requireNonNull(bufferConsumer);
|
||||||
|
this.bufferSupplier = bufferSupplier;
|
||||||
|
this.bufferConsumer = bufferConsumer;
|
||||||
|
this.sslContext = sslContext;
|
||||||
|
}
|
||||||
|
|
||||||
public final long getLastReadTime() {
|
public final long getLastReadTime() {
|
||||||
return readtime;
|
return readtime;
|
||||||
}
|
}
|
||||||
@@ -61,6 +84,9 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
return eventing.decrementAndGet();
|
return eventing.decrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract boolean isOpen();
|
||||||
|
|
||||||
public abstract boolean isTCP();
|
public abstract boolean isTCP();
|
||||||
|
|
||||||
public abstract boolean shutdownInput();
|
public abstract boolean shutdownInput();
|
||||||
@@ -84,17 +110,15 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds);
|
public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract Future<Integer> read(ByteBuffer dst);
|
public abstract int read(ByteBuffer dst) throws IOException;
|
||||||
|
|
||||||
|
public abstract void read(CompletionHandler<Integer, ByteBuffer> handler);
|
||||||
|
|
||||||
|
public abstract void read(long timeout, TimeUnit unit, CompletionHandler<Integer, ByteBuffer> handler);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract int write(ByteBuffer src) throws IOException;
|
||||||
|
|
||||||
public abstract <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract Future<Integer> write(ByteBuffer src);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler);
|
||||||
|
|
||||||
public final <A> void write(ByteBuffer[] srcs, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public final <A> void write(ByteBuffer[] srcs, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
@@ -103,6 +127,36 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
||||||
|
|
||||||
|
public void setReadBuffer(Buffer buffer) {
|
||||||
|
if (this.readBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadBuffer");
|
||||||
|
this.readBuffer = (ByteBuffer) buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer pollReadBuffer() {
|
||||||
|
ByteBuffer rs = this.readBuffer;
|
||||||
|
if (rs != null) {
|
||||||
|
this.readBuffer = null;
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
return bufferSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(Buffer buffer) {
|
||||||
|
if (buffer == null) return;
|
||||||
|
bufferConsumer.accept((ByteBuffer) buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(Buffer... buffers) {
|
||||||
|
if (buffers == null) return;
|
||||||
|
for (Buffer buffer : buffers) {
|
||||||
|
bufferConsumer.accept((ByteBuffer) buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer pollWriteBuffer() {
|
||||||
|
return bufferSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose() {//同close, 只是去掉throws IOException
|
public void dispose() {//同close, 只是去掉throws IOException
|
||||||
try {
|
try {
|
||||||
this.close();
|
this.close();
|
||||||
@@ -125,11 +179,15 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
livingCounter.decrementAndGet();
|
livingCounter.decrementAndGet();
|
||||||
livingCounter = null;
|
livingCounter = null;
|
||||||
}
|
}
|
||||||
if (beforeCloseListener != null)
|
if (beforeCloseListener != null) {
|
||||||
try {
|
try {
|
||||||
beforeCloseListener.accept(this);
|
beforeCloseListener.accept(this);
|
||||||
} catch (Exception io) {
|
} catch (Exception io) {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (this.readBuffer != null) {
|
||||||
|
bufferConsumer.accept(this.readBuffer);
|
||||||
|
}
|
||||||
if (attributes == null) return;
|
if (attributes == null) return;
|
||||||
try {
|
try {
|
||||||
for (Object obj : attributes.values()) {
|
for (Object obj : attributes.values()) {
|
||||||
@@ -174,6 +232,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
/**
|
/**
|
||||||
* 创建TCP协议客户端连接
|
* 创建TCP协议客户端连接
|
||||||
*
|
*
|
||||||
|
* @param bufferPool ByteBuffer对象池
|
||||||
* @param address 连接点子
|
* @param address 连接点子
|
||||||
* @param group 连接AsynchronousChannelGroup
|
* @param group 连接AsynchronousChannelGroup
|
||||||
* @param readTimeoutSeconds 读取超时秒数
|
* @param readTimeoutSeconds 读取超时秒数
|
||||||
@@ -181,14 +240,31 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
*
|
*
|
||||||
* @return 连接CompletableFuture
|
* @return 连接CompletableFuture
|
||||||
*/
|
*/
|
||||||
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SocketAddress address,
|
public static CompletableFuture<AsyncConnection> createTCP(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousChannelGroup group,
|
||||||
final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
return createTCP(group, null, address, readTimeoutSeconds, writeTimeoutSeconds);
|
return createTCP(bufferPool, group, null, address, readTimeoutSeconds, writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建TCP协议客户端连接
|
* 创建TCP协议客户端连接
|
||||||
*
|
*
|
||||||
|
* @param context Context
|
||||||
|
* @param address 连接点子
|
||||||
|
* @param group 连接AsynchronousChannelGroup
|
||||||
|
* @param readTimeoutSeconds 读取超时秒数
|
||||||
|
* @param writeTimeoutSeconds 写入超时秒数
|
||||||
|
*
|
||||||
|
* @return 连接CompletableFuture
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<AsyncConnection> createTCP(final Context context, final AsynchronousChannelGroup group,
|
||||||
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return createTCP(context.getBufferSupplier(), context.getBufferConsumer(), group, context.getSSLContext(), address, readTimeoutSeconds, writeTimeoutSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建TCP协议客户端连接
|
||||||
|
*
|
||||||
|
* @param bufferPool ByteBuffer对象池
|
||||||
* @param address 连接点子
|
* @param address 连接点子
|
||||||
* @param sslContext SSLContext
|
* @param sslContext SSLContext
|
||||||
* @param group 连接AsynchronousChannelGroup
|
* @param group 连接AsynchronousChannelGroup
|
||||||
@@ -197,7 +273,25 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
*
|
*
|
||||||
* @return 连接CompletableFuture
|
* @return 连接CompletableFuture
|
||||||
*/
|
*/
|
||||||
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SSLContext sslContext,
|
public static CompletableFuture<AsyncConnection> createTCP(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousChannelGroup group, final SSLContext sslContext,
|
||||||
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return createTCP(bufferPool, bufferPool, group, sslContext, address, readTimeoutSeconds, writeTimeoutSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建TCP协议客户端连接
|
||||||
|
*
|
||||||
|
* @param bufferSupplier ByteBuffer生产器
|
||||||
|
* @param bufferConsumer ByteBuffer回收器
|
||||||
|
* @param address 连接点子
|
||||||
|
* @param sslContext SSLContext
|
||||||
|
* @param group 连接AsynchronousChannelGroup
|
||||||
|
* @param readTimeoutSeconds 读取超时秒数
|
||||||
|
* @param writeTimeoutSeconds 写入超时秒数
|
||||||
|
*
|
||||||
|
* @return 连接CompletableFuture
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<AsyncConnection> createTCP(final Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer, final AsynchronousChannelGroup group, final SSLContext sslContext,
|
||||||
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
final CompletableFuture<AsyncConnection> future = new CompletableFuture<>();
|
final CompletableFuture<AsyncConnection> future = new CompletableFuture<>();
|
||||||
try {
|
try {
|
||||||
@@ -211,7 +305,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
channel.connect(address, null, new CompletionHandler<Void, Void>() {
|
channel.connect(address, null, new CompletionHandler<Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
public void completed(Void result, Void attachment) {
|
public void completed(Void result, Void attachment) {
|
||||||
future.complete(create(channel, sslContext, address, readTimeoutSeconds, writeTimeoutSeconds));
|
future.complete(new TcpAioAsyncConnection(bufferSupplier, bufferConsumer, channel, sslContext, address, readTimeoutSeconds, writeTimeoutSeconds, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -225,80 +319,109 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// public static AsyncConnection create(final Socket socket) {
|
||||||
* 通常用于 ssl socket
|
// return create(socket, null, 0, 0);
|
||||||
*
|
// }
|
||||||
* @param socket Socket对象
|
// public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
||||||
*
|
// return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, null, null);
|
||||||
* @return 连接对象
|
// }
|
||||||
*/
|
//
|
||||||
public static AsyncConnection create(final Socket socket) {
|
// public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0,
|
||||||
return create(socket, null, 0, 0);
|
// final int writeTimeoutSecond0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
}
|
// return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, livingCounter, closedCounter);
|
||||||
|
// }
|
||||||
public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
//
|
||||||
return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, null, null);
|
// public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
||||||
}
|
// final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
||||||
|
// return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
||||||
public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0,
|
// }
|
||||||
final int writeTimeoutSecond0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
//
|
||||||
return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, livingCounter, closedCounter);
|
// public static AsyncConnection create(final SocketChannel ch, final SocketAddress addr0, final Selector selector, final Context context) {
|
||||||
}
|
// return new TcpNioAsyncConnection(ch, addr0, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
||||||
|
// }
|
||||||
public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
//
|
||||||
|
// public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
||||||
|
// final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
|
// final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
// return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
||||||
|
// }
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch,
|
||||||
|
SocketAddress addr, final boolean client0,
|
||||||
final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
||||||
return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, null, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final SocketChannel ch, final SocketAddress addr0, final Selector selector, final Context context) {
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch,
|
||||||
return new TcpNioAsyncConnection(ch, addr0, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
SocketAddress addr, final boolean client0,
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
|
||||||
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, null, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch, SSLContext sslContext,
|
||||||
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
SocketAddress addr, final boolean client0,
|
||||||
return new UdpBioAsyncConnection(ch, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
||||||
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch, SSLContext sslContext,
|
||||||
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
SocketAddress addr, final boolean client0,
|
||||||
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new UdpBioAsyncConnection(ch, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch) {
|
||||||
return create(ch, null, 0, 0);
|
return create(context, ch, (SocketAddress) null, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
||||||
return new TcpAioAsyncConnection(ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
final SocketAddress addr0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
||||||
return new TcpAioAsyncConnection(ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final Context context) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds,
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
||||||
final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new TcpAioAsyncConnection(ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds,
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new TcpAioAsyncConnection(ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0,
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch) {
|
||||||
final Context context, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
return create(bufferPool, ch, null, 0, 0);
|
||||||
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.redkale.net;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
@@ -47,27 +48,6 @@ public class Context {
|
|||||||
//服务的根Servlet
|
//服务的根Servlet
|
||||||
protected final PrepareServlet prepare;
|
protected final PrepareServlet prepare;
|
||||||
|
|
||||||
//服务的监听地址
|
|
||||||
private final InetSocketAddress address;
|
|
||||||
|
|
||||||
//字符集
|
|
||||||
protected final Charset charset;
|
|
||||||
|
|
||||||
//最大连接数, 为0表示没限制
|
|
||||||
protected final int maxconns;
|
|
||||||
|
|
||||||
//请求内容的大小上限, 默认64K
|
|
||||||
protected final int maxbody;
|
|
||||||
|
|
||||||
//keep alive IO读取的超时时间
|
|
||||||
protected final int aliveTimeoutSeconds;
|
|
||||||
|
|
||||||
//IO读取的超时时间
|
|
||||||
protected final int readTimeoutSeconds;
|
|
||||||
|
|
||||||
//IO写入的超时时间
|
|
||||||
protected final int writeTimeoutSeconds;
|
|
||||||
|
|
||||||
//日志Logger
|
//日志Logger
|
||||||
protected final Logger logger;
|
protected final Logger logger;
|
||||||
|
|
||||||
@@ -80,6 +60,27 @@ public class Context {
|
|||||||
//依赖注入工厂类
|
//依赖注入工厂类
|
||||||
protected final ResourceFactory resourceFactory;
|
protected final ResourceFactory resourceFactory;
|
||||||
|
|
||||||
|
//最大连接数, 为0表示没限制
|
||||||
|
protected int maxconns;
|
||||||
|
|
||||||
|
//请求内容的大小上限, 默认64K
|
||||||
|
protected int maxbody;
|
||||||
|
|
||||||
|
//keep alive IO读取的超时时间
|
||||||
|
protected int aliveTimeoutSeconds;
|
||||||
|
|
||||||
|
//IO读取的超时时间
|
||||||
|
protected int readTimeoutSeconds;
|
||||||
|
|
||||||
|
//IO写入的超时时间
|
||||||
|
protected int writeTimeoutSeconds;
|
||||||
|
|
||||||
|
//服务的监听地址
|
||||||
|
protected InetSocketAddress address;
|
||||||
|
|
||||||
|
//字符集
|
||||||
|
protected Charset charset;
|
||||||
|
|
||||||
public Context(ContextConfig config) {
|
public Context(ContextConfig config) {
|
||||||
this(config.serverStartTime, config.logger, config.executor, config.sslContext,
|
this(config.serverStartTime, config.logger, config.executor, config.sslContext,
|
||||||
config.bufferCapacity, config.bufferPool, config.responsePool, config.maxconns, config.maxbody,
|
config.bufferCapacity, config.bufferPool, config.responsePool, config.maxconns, config.maxbody,
|
||||||
@@ -147,6 +148,14 @@ public class Context {
|
|||||||
executor.execute(r);
|
executor.execute(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCorePoolSize() {
|
||||||
|
return executor.getCorePoolSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadFactory getThreadFactory() {
|
||||||
|
return executor.getThreadFactory();
|
||||||
|
}
|
||||||
|
|
||||||
public int getBufferCapacity() {
|
public int getBufferCapacity() {
|
||||||
return bufferCapacity;
|
return bufferCapacity;
|
||||||
}
|
}
|
||||||
@@ -155,7 +164,7 @@ public class Context {
|
|||||||
return bufferPool;
|
return bufferPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Consumer<ByteBuffer> getBufferConsumer() {
|
public Consumer<ByteBuffer> getBufferConsumer() {
|
||||||
return bufferPool;
|
return bufferPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +172,18 @@ public class Context {
|
|||||||
return bufferPool.get();
|
return bufferPool.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void offerBuffer(ByteBuffer buffer) {
|
public void offerBuffer(ByteBuffer buffer) {
|
||||||
bufferPool.accept(buffer);
|
bufferPool.accept(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void offerBuffer(ByteBuffer... buffers) {
|
public void offerBuffer(ByteBuffer... buffers) {
|
||||||
|
if (buffers == null) return;
|
||||||
|
for (ByteBuffer buffer : buffers) {
|
||||||
|
bufferPool.accept(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(Collection<ByteBuffer> buffers) {
|
||||||
if (buffers == null) return;
|
if (buffers == null) return;
|
||||||
for (ByteBuffer buffer : buffers) {
|
for (ByteBuffer buffer : buffers) {
|
||||||
bufferPool.accept(buffer);
|
bufferPool.accept(buffer);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.io.IOException;
|
|||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
@@ -41,26 +42,24 @@ public class PrepareRunner implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final boolean keepalive = response != null;
|
final boolean keepalive = response != null;
|
||||||
final PrepareServlet prepare = context.prepare;
|
|
||||||
final ObjectPool<? extends Response> responsePool = context.responsePool;
|
final ObjectPool<? extends Response> responsePool = context.responsePool;
|
||||||
if (data != null) { //BIO模式的UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了
|
if (data != null) { //BIO模式的UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了
|
||||||
if (response == null) response = responsePool.get();
|
if (response == null) response = responsePool.get();
|
||||||
try {
|
try {
|
||||||
response.init(channel);
|
response.init(channel);
|
||||||
prepare.prepare(data, response.request, response);
|
codec(data, response);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
context.logger.log(Level.WARNING, "prepare servlet abort, forece to close channel ", t);
|
context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t);
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response == null) response = responsePool.get();
|
if (response == null) response = responsePool.get();
|
||||||
final ByteBuffer buffer = response.request.pollReadBuffer();
|
|
||||||
try {
|
try {
|
||||||
channel.read(buffer, keepalive ? context.getAliveTimeoutSeconds() : 0, TimeUnit.SECONDS, null,
|
channel.read(keepalive ? context.getAliveTimeoutSeconds() : context.getReadTimeoutSeconds(), TimeUnit.SECONDS,
|
||||||
new CompletionHandler<Integer, Void>() {
|
new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer count, Void attachment1) {
|
public void completed(Integer count, ByteBuffer buffer) {
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
response.request.offerReadBuffer(buffer);
|
response.request.offerReadBuffer(buffer);
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
@@ -75,39 +74,90 @@ public class PrepareRunner implements Runnable {
|
|||||||
// System.println(new String(bs));
|
// System.println(new String(bs));
|
||||||
// }
|
// }
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
response.init(channel);
|
|
||||||
try {
|
try {
|
||||||
prepare.prepare(buffer, response.request, response);
|
response.init(channel);
|
||||||
|
codec(buffer, response);
|
||||||
} catch (Throwable t) { //此处不可 context.offerBuffer(buffer); 以免prepare.prepare内部异常导致重复 offerBuffer
|
} catch (Throwable t) { //此处不可 context.offerBuffer(buffer); 以免prepare.prepare内部异常导致重复 offerBuffer
|
||||||
context.logger.log(Level.WARNING, "prepare servlet abort, forece to close channel ", t);
|
context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t);
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer buffer) {
|
||||||
response.request.offerReadBuffer(buffer);
|
response.request.offerReadBuffer(buffer);
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
if (exc != null && context.logger.isLoggable(Level.FINEST)) {
|
if (exc != null && context.logger.isLoggable(Level.FINEST)) {
|
||||||
context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, forece to close channel ", exc);
|
context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, force to close channel ", exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception te) {
|
} catch (Exception te) {
|
||||||
response.request.offerReadBuffer(buffer);
|
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
if (te != null && context.logger.isLoggable(Level.FINEST)) {
|
if (te != null && context.logger.isLoggable(Level.FINEST)) {
|
||||||
context.logger.log(Level.FINEST, "Servlet read channel erroneous, forece to close channel ", te);
|
context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void prepare(ByteBuffer buffer, Request request, Response response) throws IOException {
|
protected void codec(final ByteBuffer buffer, final Response response) throws IOException {
|
||||||
context.prepare.prepare(buffer, request, response);
|
final Request request = response.request;
|
||||||
|
final PrepareServlet preparer = context.prepare;
|
||||||
|
preparer.executeCounter.incrementAndGet();
|
||||||
|
final int rs = request.readHeader(buffer);
|
||||||
|
if (rs < 0) { //表示数据格式不正确
|
||||||
|
channel.offerBuffer(buffer);
|
||||||
|
if (rs != Integer.MIN_VALUE) preparer.illRequestCounter.incrementAndGet();
|
||||||
|
response.finish(true);
|
||||||
|
} else if (rs == 0) {
|
||||||
|
if (buffer.hasRemaining()) {
|
||||||
|
request.setMoredata(buffer);
|
||||||
|
} else {
|
||||||
|
response.request.offerReadBuffer(buffer);
|
||||||
|
}
|
||||||
|
preparer.prepare(request, response);
|
||||||
|
} else {
|
||||||
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(buffer);
|
||||||
|
final AtomicInteger ai = new AtomicInteger(rs);
|
||||||
|
channel.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
|
attachment.flip();
|
||||||
|
ai.addAndGet(-request.readBody(attachment));
|
||||||
|
if (ai.get() > 0) {
|
||||||
|
attachment.clear();
|
||||||
|
channel.setReadBuffer(attachment);
|
||||||
|
channel.read(this);
|
||||||
|
} else {
|
||||||
|
if (attachment.hasRemaining()) {
|
||||||
|
request.setMoredata(attachment);
|
||||||
|
} else {
|
||||||
|
response.request.offerReadBuffer(attachment);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
preparer.prepare(request, response);
|
||||||
|
} catch (Throwable t) { //此处不可 context.offerBuffer(buffer); 以免preparer.prepare内部异常导致重复 offerBuffer
|
||||||
|
context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t);
|
||||||
|
response.finish(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
|
preparer.illRequestCounter.incrementAndGet();
|
||||||
|
response.request.offerReadBuffer(attachment);
|
||||||
|
response.finish(true);
|
||||||
|
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, force to close channel ", exc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initResponse(Response response, AsyncConnection channel) {
|
protected void initResponse(Response response, AsyncConnection channel) {
|
||||||
|
|||||||
@@ -6,12 +6,9 @@
|
|||||||
package org.redkale.net;
|
package org.redkale.net;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.*;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.logging.*;
|
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -210,63 +207,11 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
|
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
|
||||||
|
|
||||||
public void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
|
public final void prepare(final R request, final P response) throws IOException {
|
||||||
executeCounter.incrementAndGet();
|
request.prepare();
|
||||||
final int rs = request.readHeader(buffer);
|
response.filter = this.headFilter;
|
||||||
if (rs < 0) {
|
response.servlet = this;
|
||||||
request.offerReadBuffer(buffer);
|
response.nextEvent();
|
||||||
if (rs != Integer.MIN_VALUE) illRequestCounter.incrementAndGet();
|
|
||||||
response.finish(true);
|
|
||||||
} else if (rs == 0) {
|
|
||||||
if (buffer.hasRemaining()) {
|
|
||||||
request.setMoredata(buffer);
|
|
||||||
} else {
|
|
||||||
request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
request.prepare();
|
|
||||||
response.filter = this.headFilter;
|
|
||||||
response.servlet = this;
|
|
||||||
response.nextEvent();
|
|
||||||
} else {
|
|
||||||
buffer.clear();
|
|
||||||
final AtomicInteger ai = new AtomicInteger(rs);
|
|
||||||
request.channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
|
||||||
buffer.flip();
|
|
||||||
ai.addAndGet(-request.readBody(buffer));
|
|
||||||
if (ai.get() > 0) {
|
|
||||||
buffer.clear();
|
|
||||||
request.channel.read(buffer, buffer, this);
|
|
||||||
} else {
|
|
||||||
if (buffer.hasRemaining()) {
|
|
||||||
request.setMoredata(buffer);
|
|
||||||
} else {
|
|
||||||
request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
request.prepare();
|
|
||||||
try {
|
|
||||||
response.filter = PrepareServlet.this.headFilter;
|
|
||||||
response.servlet = PrepareServlet.this;
|
|
||||||
response.nextEvent();
|
|
||||||
} catch (Exception e) {
|
|
||||||
illRequestCounter.incrementAndGet();
|
|
||||||
response.finish(true);
|
|
||||||
request.context.logger.log(Level.WARNING, "prepare servlet abort, forece to close channel ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
|
||||||
illRequestCounter.incrementAndGet();
|
|
||||||
request.offerReadBuffer(buffer);
|
|
||||||
response.finish(true);
|
|
||||||
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, forece to close channel ", exc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AnyValue getServletConf(Servlet servlet) {
|
protected AnyValue getServletConf(Servlet servlet) {
|
||||||
|
|||||||
@@ -73,13 +73,13 @@ public abstract class ProtocolServer {
|
|||||||
} else if ("aio".equalsIgnoreCase(netimpl)) {
|
} else if ("aio".equalsIgnoreCase(netimpl)) {
|
||||||
return new TcpAioProtocolServer(context);
|
return new TcpAioProtocolServer(context);
|
||||||
} else if ("nio".equalsIgnoreCase(netimpl)) {
|
} else if ("nio".equalsIgnoreCase(netimpl)) {
|
||||||
return new TcpNioProtocolServer(context);
|
return null;// return new TcpNioProtocolServer(context);
|
||||||
}
|
}
|
||||||
} else if ("UDP".equalsIgnoreCase(protocol)) {
|
} else if ("UDP".equalsIgnoreCase(protocol)) {
|
||||||
if (netimpl == null || netimpl.isEmpty()) {
|
if (netimpl == null || netimpl.isEmpty()) {
|
||||||
return new UdpBioProtocolServer(context);
|
return null;// return new UdpBioProtocolServer(context);
|
||||||
} else if ("bio".equalsIgnoreCase(netimpl)) {
|
} else if ("bio".equalsIgnoreCase(netimpl)) {
|
||||||
return new UdpBioProtocolServer(context);
|
return null;// return new UdpBioProtocolServer(context);
|
||||||
}
|
}
|
||||||
} else if (netimpl == null || netimpl.isEmpty()) {
|
} else if (netimpl == null || netimpl.isEmpty()) {
|
||||||
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
|
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
protected ByteBuffer writeBodyBuffer;
|
protected ByteBuffer writeBodyBuffer;
|
||||||
|
|
||||||
private boolean inited = true;
|
private volatile boolean inited = true;
|
||||||
|
|
||||||
protected Object output; //输出的结果对象
|
protected Object output; //输出的结果对象
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import java.text.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import org.redkale.net.Filter;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -287,6 +288,74 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
|
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void changeAddress(final InetSocketAddress addr) throws IOException {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
Objects.requireNonNull(addr);
|
||||||
|
final InetSocketAddress oldAddress = context.address;
|
||||||
|
final ProtocolServer oldServerChannel = this.serverChannel;
|
||||||
|
context.address = addr;
|
||||||
|
ProtocolServer newServerChannel = null;
|
||||||
|
try {
|
||||||
|
newServerChannel = ProtocolServer.create(this.protocol, context, this.serverClassLoader, config == null ? null : config.getValue("netimpl"));
|
||||||
|
newServerChannel.open(config);
|
||||||
|
newServerChannel.bind(addr, backlog);
|
||||||
|
newServerChannel.accept();
|
||||||
|
} catch (IOException e) {
|
||||||
|
context.address = oldAddress;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
this.address = context.address;
|
||||||
|
this.serverChannel = newServerChannel;
|
||||||
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol))
|
||||||
|
+ " change address listen: " + address + ", started in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
if (oldServerChannel != null) {
|
||||||
|
new Thread() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10_000);
|
||||||
|
oldServerChannel.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "Server.changeInetSocketAddress(addr=" + addr + ") error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeMaxconns(final int newmaxconns) {
|
||||||
|
this.maxconns = newmaxconns;
|
||||||
|
if (this.context != null) this.context.maxconns = newmaxconns;
|
||||||
|
if (this.serverChannel != null) this.serverChannel.maxconns = newmaxconns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeCharset(final Charset newcharset) {
|
||||||
|
this.charset = newcharset;
|
||||||
|
if (this.context != null) this.context.charset = newcharset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeMaxbody(final int newmaxbody) {
|
||||||
|
this.maxbody = newmaxbody;
|
||||||
|
if (this.context != null) this.context.maxbody = newmaxbody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeReadTimeoutSeconds(final int newReadTimeoutSeconds) {
|
||||||
|
this.readTimeoutSeconds = newReadTimeoutSeconds;
|
||||||
|
if (this.context != null) this.context.readTimeoutSeconds = newReadTimeoutSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeWriteTimeoutSeconds(final int newWriteTimeoutSeconds) {
|
||||||
|
this.writeTimeoutSeconds = newWriteTimeoutSeconds;
|
||||||
|
if (this.context != null) this.context.writeTimeoutSeconds = newWriteTimeoutSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeAliveTimeoutSeconds(final int newAliveTimeoutSeconds) {
|
||||||
|
this.aliveTimeoutSeconds = newAliveTimeoutSeconds;
|
||||||
|
if (this.context != null) this.context.aliveTimeoutSeconds = newAliveTimeoutSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract C createContext();
|
protected abstract C createContext();
|
||||||
|
|
||||||
public void shutdown() throws IOException {
|
public void shutdown() throws IOException {
|
||||||
@@ -412,7 +481,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
classLoader.addURL(url);
|
classLoader.addURL(url);
|
||||||
}
|
}
|
||||||
List<URL> list = new ArrayList<>(set);
|
List<URL> list = new ArrayList<>(set);
|
||||||
Collections.sort(list, (URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));
|
list.sort((URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));
|
||||||
return list.toArray(new URL[list.size()]);
|
return list.toArray(new URL[list.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.nio.channels.*;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,11 +36,12 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
|
|
||||||
private BlockingQueue<WriteEntry> writeQueue;
|
private BlockingQueue<WriteEntry> writeQueue;
|
||||||
|
|
||||||
public TcpAioAsyncConnection(final AsynchronousSocketChannel ch, SSLContext sslContext,
|
public TcpAioAsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer,
|
||||||
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds,
|
final AsynchronousSocketChannel ch, final SSLContext sslContext, final SocketAddress addr0,
|
||||||
|
final int readTimeoutSeconds, final int writeTimeoutSeconds,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
super(bufferSupplier, bufferConsumer, sslContext);
|
||||||
this.channel = ch;
|
this.channel = ch;
|
||||||
this.sslContext = sslContext;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
this.readTimeoutSeconds = readTimeoutSeconds;
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
||||||
SocketAddress addr = addr0;
|
SocketAddress addr = addr0;
|
||||||
@@ -91,24 +93,38 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
this.readtime = System.currentTimeMillis();
|
this.readtime = System.currentTimeMillis();
|
||||||
|
ByteBuffer dst = pollReadBuffer();
|
||||||
if (readTimeoutSeconds > 0) {
|
if (readTimeoutSeconds > 0) {
|
||||||
channel.read(dst, readTimeoutSeconds, TimeUnit.SECONDS, attachment, handler);
|
channel.read(dst, readTimeoutSeconds, TimeUnit.SECONDS, dst, handler);
|
||||||
} else {
|
} else {
|
||||||
channel.read(dst, attachment, handler);
|
channel.read(dst, dst, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(long timeout, TimeUnit unit, CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
this.readtime = System.currentTimeMillis();
|
this.readtime = System.currentTimeMillis();
|
||||||
channel.read(dst, timeout < 0 ? 0 : timeout, unit, attachment, handler);
|
ByteBuffer dst = pollReadBuffer();
|
||||||
|
channel.read(dst, timeout < 0 ? 0 : timeout, unit, dst, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <A> void nextWrite(A attachment) {
|
private <A> void nextWrite(Throwable exc, A attachment) {
|
||||||
BlockingQueue<WriteEntry> queue = this.writeQueue;
|
BlockingQueue<WriteEntry> queue = this.writeQueue;
|
||||||
|
if (queue != null && exc != null && !isOpen()) {
|
||||||
|
WriteEntry entry;
|
||||||
|
while ((entry = queue.poll()) != null) {
|
||||||
|
try {
|
||||||
|
entry.writeHandler.failed(exc, entry.writeAttachment);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
WriteEntry entry = queue == null ? null : queue.poll();
|
WriteEntry entry = queue == null ? null : queue.poll();
|
||||||
|
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
try {
|
try {
|
||||||
if (entry.writeOneBuffer == null) {
|
if (entry.writeOneBuffer == null) {
|
||||||
@@ -223,13 +239,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Future<Integer> read(ByteBuffer dst) {
|
public final int read(ByteBuffer dst) throws IOException {
|
||||||
return channel.read(dst);
|
try {
|
||||||
|
return channel.read(dst).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Future<Integer> write(ByteBuffer src) {
|
public final int write(ByteBuffer src) throws IOException {
|
||||||
return channel.write(src);
|
try {
|
||||||
|
return channel.write(src).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -300,18 +324,27 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
failed(e, attachment);
|
failed(e, attachment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.completed(writeCount, attachment);
|
writeHandler.completed(writeCount, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(null, attachment);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.completed(result.intValue(), attachment);
|
writeHandler.completed(result.intValue(), attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(null, attachment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.failed(exc, attachment);
|
writeHandler.failed(exc, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(exc, attachment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -338,14 +371,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
failed(e, attachment);
|
failed(e, attachment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.completed(result, attachment);
|
writeHandler.completed(result, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(null, attachment);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.failed(exc, attachment);
|
writeHandler.failed(exc, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(exc, attachment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,13 +92,13 @@ public class TcpAioProtocolServer extends ProtocolServer {
|
|||||||
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
||||||
channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
||||||
channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
||||||
} catch (IOException e) {
|
|
||||||
context.logger.log(Level.INFO, channel + " setOption error", e);
|
AsyncConnection conn = new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), channel,
|
||||||
|
context.getSSLContext(), null, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
|
context.runAsync(new PrepareRunner(context, conn, null, null));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
context.logger.log(Level.INFO, channel + " accept error", e);
|
||||||
}
|
}
|
||||||
AsyncConnection conn = new TcpAioAsyncConnection(channel, context.sslContext, null, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
|
||||||
conn.livingCounter = livingCounter;
|
|
||||||
conn.closedCounter = closedCounter;
|
|
||||||
context.runAsync(new PrepareRunner(context, conn, null, null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,240 +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;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpBioAsyncConnection extends AsyncConnection {
|
|
||||||
|
|
||||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
|
||||||
|
|
||||||
private static Set<SocketOption<?>> defaultOptions() {
|
|
||||||
HashSet<SocketOption<?>> set = new HashSet<>(5);
|
|
||||||
set.add(StandardSocketOptions.SO_SNDBUF);
|
|
||||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
|
||||||
set.add(StandardSocketOptions.SO_KEEPALIVE);
|
|
||||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
|
||||||
set.add(StandardSocketOptions.TCP_NODELAY);
|
|
||||||
return Collections.unmodifiableSet(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readTimeoutSeconds;
|
|
||||||
|
|
||||||
private int writeTimeoutSeconds;
|
|
||||||
|
|
||||||
private final Socket socket;
|
|
||||||
|
|
||||||
private final ReadableByteChannel readChannel;
|
|
||||||
|
|
||||||
private final WritableByteChannel writeChannel;
|
|
||||||
|
|
||||||
private final SocketAddress remoteAddress;
|
|
||||||
|
|
||||||
public TcpBioAsyncConnection(final Socket socket, final SocketAddress addr0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
this.socket = socket;
|
|
||||||
ReadableByteChannel rc = null;
|
|
||||||
WritableByteChannel wc = null;
|
|
||||||
try {
|
|
||||||
socket.setSoTimeout(Math.max(readTimeoutSeconds0, writeTimeoutSeconds0));
|
|
||||||
rc = Channels.newChannel(socket.getInputStream());
|
|
||||||
wc = Channels.newChannel(socket.getOutputStream());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
this.readChannel = rc;
|
|
||||||
this.writeChannel = wc;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds0;
|
|
||||||
SocketAddress addr = addr0;
|
|
||||||
if (addr == null) {
|
|
||||||
try {
|
|
||||||
addr = socket.getRemoteSocketAddress();
|
|
||||||
} catch (Exception e) {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.remoteAddress = addr;
|
|
||||||
this.livingCounter = livingCounter;
|
|
||||||
this.closedCounter = closedCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTCP() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getRemoteAddress() {
|
|
||||||
return remoteAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getLocalAddress() {
|
|
||||||
return socket.getLocalSocketAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getReadTimeoutSeconds() {
|
|
||||||
return readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWriteTimeoutSeconds() {
|
|
||||||
return writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadTimeoutSeconds(int readTimeoutSeconds) {
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWriteTimeoutSeconds(int writeTimeoutSeconds) {
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownInput() {
|
|
||||||
try {
|
|
||||||
this.socket.shutdownInput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownOutput() {
|
|
||||||
try {
|
|
||||||
this.socket.shutdownOutput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean setOption(SocketOption<T> name, T value) {
|
|
||||||
try {
|
|
||||||
if (StandardSocketOptions.SO_REUSEADDR == name) {
|
|
||||||
this.socket.setReuseAddress((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_KEEPALIVE == name) {
|
|
||||||
this.socket.setKeepAlive((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.TCP_NODELAY == name) {
|
|
||||||
this.socket.setTcpNoDelay((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_RCVBUF == name) {
|
|
||||||
this.socket.setReceiveBufferSize((Integer) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_SNDBUF == name) {
|
|
||||||
this.socket.setSendBufferSize((Integer) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return defaultOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = 0;
|
|
||||||
for (int i = offset; i < offset + length; i++) {
|
|
||||||
rs += writeChannel.write(srcs[i]);
|
|
||||||
}
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = readChannel.read(dst);
|
|
||||||
this.readtime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
read(dst, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
|
||||||
try {
|
|
||||||
int rs = readChannel.read(dst);
|
|
||||||
this.readtime = System.currentTimeMillis();
|
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = writeChannel.write(src);
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
|
||||||
try {
|
|
||||||
int rs = writeChannel.write(src);
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
super.close();
|
|
||||||
this.socket.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !socket.isClosed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,366 +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;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpNioAsyncConnection extends AsyncConnection {
|
|
||||||
|
|
||||||
protected int readTimeoutSeconds;
|
|
||||||
|
|
||||||
protected int writeTimeoutSeconds;
|
|
||||||
|
|
||||||
protected final Selector selector;
|
|
||||||
|
|
||||||
protected SelectionKey key;
|
|
||||||
|
|
||||||
protected final SocketChannel channel;
|
|
||||||
|
|
||||||
protected final SocketAddress remoteAddress;
|
|
||||||
|
|
||||||
ByteBuffer readBuffer;
|
|
||||||
|
|
||||||
Object readAttachment;
|
|
||||||
|
|
||||||
CompletionHandler readHandler;
|
|
||||||
|
|
||||||
ByteBuffer writeOneBuffer;
|
|
||||||
|
|
||||||
ByteBuffer[] writeBuffers;
|
|
||||||
|
|
||||||
int writingCount;
|
|
||||||
|
|
||||||
int writeOffset;
|
|
||||||
|
|
||||||
int writeLength;
|
|
||||||
|
|
||||||
Object writeAttachment;
|
|
||||||
|
|
||||||
CompletionHandler writeHandler;
|
|
||||||
|
|
||||||
public TcpNioAsyncConnection(final SocketChannel ch, SocketAddress addr0,
|
|
||||||
final Selector selector,
|
|
||||||
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
this.channel = ch;
|
|
||||||
this.selector = selector;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds0;
|
|
||||||
SocketAddress addr = addr0;
|
|
||||||
if (addr == null) {
|
|
||||||
try {
|
|
||||||
addr = ch.getRemoteAddress();
|
|
||||||
} catch (Exception e) {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.remoteAddress = addr;
|
|
||||||
this.livingCounter = livingCounter;
|
|
||||||
this.closedCounter = closedCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadTimeoutSeconds(int readTimeoutSeconds) {
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWriteTimeoutSeconds(int writeTimeoutSeconds) {
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getReadTimeoutSeconds() {
|
|
||||||
return this.readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWriteTimeoutSeconds() {
|
|
||||||
return this.writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final SocketAddress getRemoteAddress() {
|
|
||||||
return remoteAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getLocalAddress() {
|
|
||||||
try {
|
|
||||||
return channel.getLocalAddress();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownInput() {
|
|
||||||
try {
|
|
||||||
this.channel.shutdownInput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownOutput() {
|
|
||||||
try {
|
|
||||||
this.channel.shutdownOutput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean setOption(SocketOption<T> name, T value) {
|
|
||||||
try {
|
|
||||||
this.channel.setOption(name, value);
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return this.channel.supportedOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletionHandler removeReadHandler() {
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readHandler = null;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer removeReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.readBuffer;
|
|
||||||
this.readBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object removeReadAttachment() {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
this.readAttachment = null;
|
|
||||||
return attach;
|
|
||||||
}
|
|
||||||
|
|
||||||
void completeRead(int rs) {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readBuffer = null;
|
|
||||||
this.readAttachment = null;
|
|
||||||
this.readHandler = null;
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
void faileRead(Throwable t) {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readBuffer = null;
|
|
||||||
this.readAttachment = null;
|
|
||||||
this.readHandler = null;
|
|
||||||
handler.failed(t, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletionHandler removeWriteHandler() {
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeHandler = null;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer removeWriteOneBuffer() {
|
|
||||||
ByteBuffer buffer = this.writeOneBuffer;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer[] removeWriteBuffers() {
|
|
||||||
ByteBuffer[] buffers = this.writeBuffers;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
return buffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWritingCount() {
|
|
||||||
int rs = this.writingCount;
|
|
||||||
this.writingCount = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWriteOffset() {
|
|
||||||
int rs = this.writeOffset;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWriteLength() {
|
|
||||||
int rs = this.writeLength;
|
|
||||||
this.writeLength = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object removeWriteAttachment() {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
return attach;
|
|
||||||
}
|
|
||||||
|
|
||||||
void completeWrite(int rs) {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
this.writeLength = 0;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
this.writeHandler = null;
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
void faileWrite(Throwable t) {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
this.writeLength = 0;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
this.writeHandler = null;
|
|
||||||
handler.failed(t, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.readHandler != null) throw new RuntimeException("pending read");
|
|
||||||
try {
|
|
||||||
this.readBuffer = dst;
|
|
||||||
this.readAttachment = attachment;
|
|
||||||
this.readHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_READ);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_READ);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileRead(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
read(dst, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
|
||||||
CompletableFuture future = new CompletableFuture();
|
|
||||||
read(dst, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
@Override
|
|
||||||
public void completed(Integer result, Void attachment) {
|
|
||||||
future.complete(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(Throwable exc, Void attachment) {
|
|
||||||
future.completeExceptionally(exc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.writeHandler != null) throw new RuntimeException("pending write");
|
|
||||||
try {
|
|
||||||
this.writeBuffers = srcs;
|
|
||||||
this.writeOffset = offset;
|
|
||||||
this.writeLength = length;
|
|
||||||
this.writingCount = 0;
|
|
||||||
this.writeAttachment = attachment;
|
|
||||||
this.writeHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_WRITE);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileWrite(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.writeHandler != null) throw new RuntimeException("pending write");
|
|
||||||
try {
|
|
||||||
this.writeOneBuffer = src;
|
|
||||||
this.writingCount = 0;
|
|
||||||
this.writeAttachment = attachment;
|
|
||||||
this.writeHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_WRITE);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileWrite(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
|
||||||
CompletableFuture future = new CompletableFuture();
|
|
||||||
write(src, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
@Override
|
|
||||||
public void completed(Integer result, Void attachment) {
|
|
||||||
future.complete(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(Throwable exc, Void attachment) {
|
|
||||||
future.completeExceptionally(exc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void close() throws IOException {
|
|
||||||
super.close();
|
|
||||||
channel.close();
|
|
||||||
key.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isOpen() {
|
|
||||||
return channel.isOpen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isTCP() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,370 +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;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import org.redkale.util.AnyValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 协议底层Server
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpNioProtocolServer extends ProtocolServer {
|
|
||||||
|
|
||||||
private Selector acceptSelector;
|
|
||||||
|
|
||||||
private ServerSocketChannel serverChannel;
|
|
||||||
|
|
||||||
private NioThreadWorker[] workers;
|
|
||||||
|
|
||||||
private NioThreadWorker currWorker;
|
|
||||||
|
|
||||||
private boolean running;
|
|
||||||
|
|
||||||
public TcpNioProtocolServer(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void open(AnyValue config) throws IOException {
|
|
||||||
acceptSelector = Selector.open();
|
|
||||||
this.serverChannel = ServerSocketChannel.open();
|
|
||||||
serverChannel.configureBlocking(false);
|
|
||||||
ServerSocket socket = serverChannel.socket();
|
|
||||||
socket.setReceiveBufferSize(16 * 1024);
|
|
||||||
socket.setReuseAddress(true);
|
|
||||||
|
|
||||||
final Set<SocketOption<?>> options = this.serverChannel.supportedOptions();
|
|
||||||
if (options.contains(StandardSocketOptions.TCP_NODELAY)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_KEEPALIVE)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_REUSEADDR)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_RCVBUF)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_SNDBUF)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bind(SocketAddress local, int backlog) throws IOException {
|
|
||||||
this.serverChannel.bind(local, backlog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return this.serverChannel.supportedOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
|
|
||||||
this.serverChannel.setOption(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept() throws IOException {
|
|
||||||
this.serverChannel.register(acceptSelector, SelectionKey.OP_ACCEPT);
|
|
||||||
this.running = true;
|
|
||||||
this.workers = new NioThreadWorker[Runtime.getRuntime().availableProcessors()];
|
|
||||||
final CountDownLatch wkcdl = new CountDownLatch(workers.length);
|
|
||||||
for (int i = 0; i < workers.length; i++) {
|
|
||||||
workers[i] = new NioThreadWorker(wkcdl, i + 1, workers.length);
|
|
||||||
workers[i].setDaemon(true);
|
|
||||||
workers[i].start();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < workers.length - 1; i++) { //构成环形
|
|
||||||
workers[i].next = workers[i + 1];
|
|
||||||
}
|
|
||||||
workers[workers.length - 1].next = workers[0];
|
|
||||||
currWorker = workers[0];
|
|
||||||
try {
|
|
||||||
wkcdl.await(3, TimeUnit.SECONDS);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
final CountDownLatch cdl = new CountDownLatch(1);
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
cdl.countDown();
|
|
||||||
while (running) {
|
|
||||||
try {
|
|
||||||
acceptSelector.select();
|
|
||||||
Set<SelectionKey> selectedKeys = acceptSelector.selectedKeys();
|
|
||||||
synchronized (selectedKeys) {
|
|
||||||
Iterator<?> iter = selectedKeys.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
SelectionKey key = (SelectionKey) iter.next();
|
|
||||||
iter.remove();
|
|
||||||
if (key.isAcceptable()) {
|
|
||||||
try {
|
|
||||||
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
|
|
||||||
createCounter.incrementAndGet();
|
|
||||||
livingCounter.incrementAndGet();
|
|
||||||
currWorker.addChannel(channel);
|
|
||||||
currWorker = currWorker.next;
|
|
||||||
} catch (IOException io) {
|
|
||||||
io.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
try {
|
|
||||||
cdl.await(3, TimeUnit.SECONDS);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
if (!this.running) return;
|
|
||||||
serverChannel.close();
|
|
||||||
acceptSelector.close();
|
|
||||||
for (NioThreadWorker worker : workers) {
|
|
||||||
worker.interrupt();
|
|
||||||
}
|
|
||||||
this.running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class NioThreadWorker extends Thread {
|
|
||||||
|
|
||||||
final Selector selector;
|
|
||||||
|
|
||||||
final CountDownLatch cdl;
|
|
||||||
|
|
||||||
private final Queue<TcpNioAsyncConnection> connected;
|
|
||||||
|
|
||||||
private final CopyOnWriteArrayList<TcpNioAsyncConnection> done;
|
|
||||||
|
|
||||||
protected volatile Thread ownerThread;
|
|
||||||
|
|
||||||
NioThreadWorker next;
|
|
||||||
|
|
||||||
public NioThreadWorker(final CountDownLatch cdl, int idx, int count) {
|
|
||||||
this.cdl = cdl;
|
|
||||||
String idxstr = "000000" + idx;
|
|
||||||
this.setName("NioThreadWorker:" + context.getServerAddress().getPort() + "-" + idxstr.substring(idxstr.length() - ("" + count).length()));
|
|
||||||
try {
|
|
||||||
this.selector = Selector.open();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
this.connected = new ArrayBlockingQueue<>(1000000);
|
|
||||||
this.done = new CopyOnWriteArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addChannel(SocketChannel channel) throws IOException {
|
|
||||||
TcpNioAsyncConnection conn = new TcpNioAsyncConnection(channel, null, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
|
||||||
return connected.add(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void processConnected() {
|
|
||||||
TcpNioAsyncConnection schannel;
|
|
||||||
try {
|
|
||||||
while ((schannel = connected.poll()) != null) {
|
|
||||||
SocketChannel channel = schannel.channel;
|
|
||||||
channel.configureBlocking(false);
|
|
||||||
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
|
||||||
channel.register(selector, SelectionKey.OP_READ).attach(schannel);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
synchronized (done) {
|
|
||||||
for (TcpNioAsyncConnection conn : done) {
|
|
||||||
if (conn.key != null && conn.key.isValid()) {
|
|
||||||
conn.key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSameThread() {
|
|
||||||
return this.ownerThread == Thread.currentThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
this.ownerThread = Thread.currentThread();
|
|
||||||
if (cdl != null) cdl.countDown();
|
|
||||||
while (running) {
|
|
||||||
processConnected();
|
|
||||||
try {
|
|
||||||
selector.select(50);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Set<SelectionKey> selectedKeys = selector.selectedKeys();
|
|
||||||
synchronized (selectedKeys) {
|
|
||||||
Iterator<?> iter = selectedKeys.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
SelectionKey key = (SelectionKey) iter.next();
|
|
||||||
iter.remove();
|
|
||||||
processKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processKey(SelectionKey key) {
|
|
||||||
if (key == null || !key.isValid()) return;
|
|
||||||
SocketChannel socket = (SocketChannel) key.channel();
|
|
||||||
TcpNioAsyncConnection conn = (TcpNioAsyncConnection) key.attachment();
|
|
||||||
if (!socket.isOpen()) {
|
|
||||||
if (conn == null) {
|
|
||||||
key.cancel();
|
|
||||||
} else {
|
|
||||||
conn.dispose();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (conn == null) return;
|
|
||||||
if (key.isReadable()) {
|
|
||||||
if (conn.readHandler != null) readOP(key, socket, conn);
|
|
||||||
} else if (key.isWritable()) {
|
|
||||||
if (conn.writeHandler != null) writeOP(key, socket, conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeOP(SelectionKey key) {
|
|
||||||
if (key == null) return;
|
|
||||||
TcpNioAsyncConnection conn = (TcpNioAsyncConnection) key.attachment();
|
|
||||||
try {
|
|
||||||
if (key.isValid()) {
|
|
||||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
|
||||||
socketChannel.close();
|
|
||||||
key.attach(null);
|
|
||||||
key.cancel();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
conn.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readOP(SelectionKey key, SocketChannel socket, TcpNioAsyncConnection conn) {
|
|
||||||
final CompletionHandler handler = conn.removeReadHandler();
|
|
||||||
final ByteBuffer buffer = conn.removeReadBuffer();
|
|
||||||
final Object attach = conn.removeReadAttachment();
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler);
|
|
||||||
if (handler == null || buffer == null) return;
|
|
||||||
try {
|
|
||||||
final int rs = socket.read(buffer);
|
|
||||||
{ //测试
|
|
||||||
buffer.flip();
|
|
||||||
byte[] bs = new byte[buffer.remaining()];
|
|
||||||
buffer.get(bs);
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler + "-------读内容: " + new String(bs));
|
|
||||||
}
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler + "-------read: " + rs);
|
|
||||||
context.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
handler.failed(e, attach);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
context.runAsync(() -> handler.failed(t, attach));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeOP(SelectionKey key, SocketChannel socket, TcpNioAsyncConnection conn) {
|
|
||||||
final CompletionHandler handler = conn.writeHandler;
|
|
||||||
final ByteBuffer oneBuffer = conn.removeWriteOneBuffer();
|
|
||||||
final ByteBuffer[] buffers = conn.removeWriteBuffers();
|
|
||||||
final Object attach = conn.removeWriteAttachment();
|
|
||||||
final int writingCount = conn.removeWritingCount();
|
|
||||||
final int writeOffset = conn.removeWriteOffset();
|
|
||||||
final int writeLength = conn.removeWriteLength();
|
|
||||||
if (handler == null || (oneBuffer == null && buffers == null)) return;
|
|
||||||
//System.out.println(conn + "------buffers:" + Arrays.toString(buffers) + "---onebuf:" + oneBuffer + "-------handler:" + handler);
|
|
||||||
try {
|
|
||||||
int rs = 0;
|
|
||||||
if (oneBuffer == null) {
|
|
||||||
int offset = writeOffset;
|
|
||||||
int length = writeLength;
|
|
||||||
rs = (int) socket.write(buffers, offset, length);
|
|
||||||
boolean over = true;
|
|
||||||
int end = offset + length;
|
|
||||||
for (int i = offset; i < end; i++) {
|
|
||||||
if (buffers[i].hasRemaining()) {
|
|
||||||
over = false;
|
|
||||||
length -= i - offset;
|
|
||||||
offset = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!over) {
|
|
||||||
conn.writingCount += rs;
|
|
||||||
conn.writeHandler = handler;
|
|
||||||
conn.writeAttachment = attach;
|
|
||||||
conn.writeBuffers = buffers;
|
|
||||||
conn.writeOffset = offset;
|
|
||||||
conn.writeLength = length;
|
|
||||||
key.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE);
|
|
||||||
key.selector().wakeup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rs = socket.write(oneBuffer);
|
|
||||||
if (oneBuffer.hasRemaining()) {
|
|
||||||
conn.writingCount += rs;
|
|
||||||
conn.writeHandler = handler;
|
|
||||||
conn.writeAttachment = attach;
|
|
||||||
conn.writeOneBuffer = oneBuffer;
|
|
||||||
key.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE);
|
|
||||||
key.selector().wakeup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
conn.removeWriteHandler();
|
|
||||||
key.interestOps(SelectionKey.OP_READ); //OP_CONNECT
|
|
||||||
final int rs0 = rs + writingCount;
|
|
||||||
//System.out.println(conn + "------buffers:" + Arrays.toString(buffers) + "---onebuf:" + oneBuffer + "-------handler:" + handler + "-------write: " + rs);
|
|
||||||
context.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
handler.completed(rs0, attach);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
handler.failed(e, attach);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
context.runAsync(() -> handler.failed(t, attach));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -215,12 +215,12 @@ public final class Transport {
|
|||||||
DatagramChannel channel = DatagramChannel.open();
|
DatagramChannel channel = DatagramChannel.open();
|
||||||
channel.configureBlocking(true);
|
channel.configureBlocking(true);
|
||||||
channel.connect(udpaddr);
|
channel.connect(udpaddr);
|
||||||
return CompletableFuture.completedFuture(AsyncConnection.create(channel, udpaddr, true, factory.readTimeoutSeconds, factory.writeTimeoutSeconds));
|
return CompletableFuture.completedFuture(AsyncConnection.create(bufferPool, channel, sslContext, udpaddr, true, factory.readTimeoutSeconds, factory.writeTimeoutSeconds));
|
||||||
}
|
}
|
||||||
if (!rand) { //指定地址
|
if (!rand) { //指定地址
|
||||||
TransportNode node = findTransportNode(addr);
|
TransportNode node = findTransportNode(addr);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return AsyncConnection.createTCP(group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
return AsyncConnection.createTCP(bufferPool, group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
final BlockingQueue<AsyncConnection> queue = node.conns;
|
final BlockingQueue<AsyncConnection> queue = node.conns;
|
||||||
if (!queue.isEmpty()) {
|
if (!queue.isEmpty()) {
|
||||||
@@ -233,7 +233,7 @@ public final class Transport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AsyncConnection.createTCP(group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
return AsyncConnection.createTCP(bufferPool, group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------随机取地址------------------------
|
//---------------------随机取地址------------------------
|
||||||
@@ -266,7 +266,7 @@ public final class Transport {
|
|||||||
@Override
|
@Override
|
||||||
public void completed(Void result, TransportNode attachment) {
|
public void completed(Void result, TransportNode attachment) {
|
||||||
attachment.disabletime = 0;
|
attachment.disabletime = 0;
|
||||||
AsyncConnection asyncConn = AsyncConnection.create(channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
AsyncConnection asyncConn = AsyncConnection.create(bufferPool, channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
||||||
} else {
|
} else {
|
||||||
@@ -319,7 +319,7 @@ public final class Transport {
|
|||||||
public void completed(Void result, TransportNode attachment) {
|
public void completed(Void result, TransportNode attachment) {
|
||||||
try {
|
try {
|
||||||
attachment.disabletime = 0;
|
attachment.disabletime = 0;
|
||||||
AsyncConnection asyncConn = AsyncConnection.create(channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
AsyncConnection asyncConn = AsyncConnection.create(bufferPool, channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
||||||
} else {
|
} else {
|
||||||
@@ -371,18 +371,19 @@ public final class Transport {
|
|||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
if (handler != null) handler.completed(result, att);
|
if (handler != null) handler.completed(result, att);
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(false, conn);
|
offerConnection(false, conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(true, conn);
|
offerConnection(true, conn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -391,7 +392,7 @@ public final class Transport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(true, conn);
|
offerConnection(true, conn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -393,33 +393,34 @@ public class TransportFactory {
|
|||||||
final BlockingQueue<AsyncConnection> localqueue = queue;
|
final BlockingQueue<AsyncConnection> localqueue = queue;
|
||||||
localconn.write(sendBuffer, sendBuffer, new CompletionHandler<Integer, ByteBuffer>() {
|
localconn.write(sendBuffer, sendBuffer, new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer buffer) {
|
public void completed(Integer result, ByteBuffer wbuffer) {
|
||||||
if (buffer.hasRemaining()) {
|
if (wbuffer.hasRemaining()) {
|
||||||
localconn.write(buffer, buffer, this);
|
localconn.write(wbuffer, wbuffer, this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ByteBuffer pongBuffer = bufferPool.get();
|
localconn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
localconn.read(pongBuffer, pongBuffer, new CompletionHandler<Integer, ByteBuffer>() {
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer pongBuffer) {
|
||||||
if (counter > 3) {
|
if (counter > 3) {
|
||||||
bufferPool.accept(attachment);
|
localconn.offerBuffer(pongBuffer);
|
||||||
localconn.dispose();
|
localconn.dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pongLength > 0 && attachment.position() < pongLength) {
|
if (pongLength > 0 && pongBuffer.position() < pongLength) {
|
||||||
counter++;
|
counter++;
|
||||||
localconn.read(pongBuffer, pongBuffer, this);
|
localconn.setReadBuffer(pongBuffer);
|
||||||
|
localconn.read(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bufferPool.accept(attachment);
|
localconn.offerBuffer(pongBuffer);
|
||||||
localqueue.offer(localconn);
|
localqueue.offer(localconn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer pongBuffer) {
|
||||||
|
localconn.offerBuffer(pongBuffer);
|
||||||
localconn.dispose();
|
localconn.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import java.nio.channels.*;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.*;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -32,9 +34,11 @@ public class UdpBioAsyncConnection extends AsyncConnection {
|
|||||||
|
|
||||||
private final boolean client;
|
private final boolean client;
|
||||||
|
|
||||||
public UdpBioAsyncConnection(final DatagramChannel ch, SocketAddress addr0,
|
public UdpBioAsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer,
|
||||||
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
final DatagramChannel ch, final SSLContext sslContext, SocketAddress addr0, final boolean client0,
|
||||||
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
super(bufferSupplier, bufferConsumer, sslContext);
|
||||||
this.channel = ch;
|
this.channel = ch;
|
||||||
this.client = client0;
|
this.client = client0;
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
this.readTimeoutSeconds = readTimeoutSeconds0;
|
||||||
@@ -127,30 +131,27 @@ public class UdpBioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
|
ByteBuffer dst = pollReadBuffer();
|
||||||
try {
|
try {
|
||||||
int rs = channel.read(dst);
|
int rs = channel.read(dst);
|
||||||
this.readtime = System.currentTimeMillis();
|
this.readtime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, dst);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(long timeout, TimeUnit unit, CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
read(dst, attachment, handler);
|
read(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
try {
|
int rs = channel.read(dst);
|
||||||
int rs = channel.read(dst);
|
this.readtime = System.currentTimeMillis();
|
||||||
this.readtime = System.currentTimeMillis();
|
return rs;
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -165,14 +166,10 @@ public class UdpBioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
public int write(ByteBuffer src) throws IOException {
|
||||||
try {
|
int rs = channel.send(src, remoteAddress);
|
||||||
int rs = channel.send(src, remoteAddress);
|
this.writetime = System.currentTimeMillis();
|
||||||
this.writetime = System.currentTimeMillis();
|
return rs;
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ public class UdpBioProtocolServer extends ProtocolServer {
|
|||||||
try {
|
try {
|
||||||
SocketAddress address = serchannel.receive(buffer);
|
SocketAddress address = serchannel.receive(buffer);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
AsyncConnection conn = new UdpBioAsyncConnection(serchannel, address, false, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
AsyncConnection conn = new UdpBioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), serchannel,
|
||||||
|
context.getSSLContext(), address, false, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
context.runAsync(new PrepareRunner(context, conn, buffer, null));
|
context.runAsync(new PrepareRunner(context, conn, buffer, null));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
context.offerBuffer(buffer);
|
context.offerBuffer(buffer);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import java.util.concurrent.*;
|
|||||||
*/
|
*/
|
||||||
public class WorkThread extends Thread {
|
public class WorkThread extends Thread {
|
||||||
|
|
||||||
|
protected Thread localThread;
|
||||||
|
|
||||||
private final ExecutorService executor;
|
private final ExecutorService executor;
|
||||||
|
|
||||||
public WorkThread(ExecutorService executor, Runnable runner) {
|
public WorkThread(ExecutorService executor, Runnable runner) {
|
||||||
@@ -32,4 +34,19 @@ public class WorkThread extends Thread {
|
|||||||
public ExecutorService getExecutor() {
|
public ExecutorService getExecutor() {
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
this.localThread = Thread.currentThread();
|
||||||
|
super.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inSameThread() {
|
||||||
|
return this.localThread == Thread.currentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inSameThread(Thread thread) {
|
||||||
|
return this.localThread == thread;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.net.http;
|
package org.redkale.net.http;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import org.redkale.asm.MethodDebugVisitor;
|
import org.redkale.asm.MethodDebugVisitor;
|
||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
|
||||||
import org.redkale.asm.*;
|
import org.redkale.asm.*;
|
||||||
import static org.redkale.asm.Opcodes.*;
|
import static org.redkale.asm.Opcodes.*;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
@@ -49,21 +47,6 @@ public class HttpContext extends Context {
|
|||||||
return responsePool;
|
return responsePool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Consumer<ByteBuffer> getBufferConsumer() {
|
|
||||||
return super.getBufferConsumer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void offerBuffer(ByteBuffer buffer) {
|
|
||||||
super.offerBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void offerBuffer(ByteBuffer... buffers) {
|
|
||||||
super.offerBuffer(buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected <H extends CompletionHandler> Creator<H> loadAsyncHandlerCreator(Class<H> handlerClass) {
|
protected <H extends CompletionHandler> Creator<H> loadAsyncHandlerCreator(Class<H> handlerClass) {
|
||||||
Creator<H> creator = asyncHandlerCreators.get(handlerClass);
|
Creator<H> creator = asyncHandlerCreators.get(handlerClass);
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
if (forbidURIMaps != null && forbidURIMaps.containsKey(urlreg)) return false;
|
if (forbidURIMaps != null && forbidURIMaps.containsKey(urlreg)) return false;
|
||||||
if (forbidURIMaps == null) forbidURIMaps = new HashMap<>();
|
if (forbidURIMaps == null) forbidURIMaps = new HashMap<>();
|
||||||
String mapping = urlreg;
|
String mapping = urlreg;
|
||||||
if (Utility.contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
|
if (Utility.contains(mapping, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
|
||||||
if (mapping.endsWith("/*")) {
|
if (mapping.endsWith("/*")) {
|
||||||
mapping = mapping.substring(0, mapping.length() - 1) + ".*";
|
mapping = mapping.substring(0, mapping.length() - 1) + ".*";
|
||||||
} else {
|
} else {
|
||||||
@@ -254,7 +254,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
logger.log(Level.WARNING, "init HttpRender(" + renderType + ") error", e);
|
logger.log(Level.WARNING, "init HttpRender(" + renderType + ") error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(renders, (o1, o2) -> o1.getType().isAssignableFrom(o2.getType()) ? 1 : -1);
|
renders.sort((o1, o2) -> o1.getType().isAssignableFrom(o2.getType()) ? 1 : -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,7 +311,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
}
|
}
|
||||||
servlet.execute(request, response);
|
servlet.execute(request, response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
request.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
|
request.getContext().getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request, e);
|
||||||
response.finish(500, null);
|
response.finish(500, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ public class HttpResourceServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serRoot(String rootstr) {
|
public void setRoot(String rootstr) {
|
||||||
if (rootstr == null) return;
|
if (rootstr == null) return;
|
||||||
try {
|
try {
|
||||||
this.root = new File(rootstr).getCanonicalFile();
|
this.root = new File(rootstr).getCanonicalFile();
|
||||||
@@ -170,7 +170,7 @@ public class HttpResourceServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serRoot(File file) {
|
public void setRoot(File file) {
|
||||||
if (file == null) return;
|
if (file == null) return;
|
||||||
try {
|
try {
|
||||||
this.root = file.getCanonicalFile();
|
this.root = file.getCanonicalFile();
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
return Utility.createAsyncHandler((v, a) -> {
|
return Utility.createAsyncHandler((v, a) -> {
|
||||||
finish(v);
|
finish(v);
|
||||||
}, (t, a) -> {
|
}, (t, a) -> {
|
||||||
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request + ", result is CompletionHandler", (Throwable) t);
|
context.getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request + ", result is CompletionHandler", (Throwable) t);
|
||||||
finish(500, null);
|
finish(500, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -471,7 +471,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
} else if (obj instanceof CompletableFuture) {
|
} else if (obj instanceof CompletableFuture) {
|
||||||
((CompletableFuture) obj).whenComplete((v, e) -> {
|
((CompletableFuture) obj).whenComplete((v, e) -> {
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request + ", result is CompletableFuture", (Throwable) e);
|
context.getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request + ", result is CompletableFuture", (Throwable) e);
|
||||||
finish(500, null);
|
finish(500, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -489,7 +489,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
try {
|
try {
|
||||||
finish((File) obj);
|
finish((File) obj);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
context.getLogger().log(Level.WARNING, "HttpServlet finish File occur, forece to close channel. request = " + getRequest(), e);
|
context.getLogger().log(Level.WARNING, "HttpServlet finish File occur, force to close channel. request = " + getRequest(), e);
|
||||||
finish(500, null);
|
finish(500, null);
|
||||||
}
|
}
|
||||||
} else if (obj instanceof HttpResult) {
|
} else if (obj instanceof HttpResult) {
|
||||||
@@ -941,7 +941,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
}
|
}
|
||||||
if (request.newsessionid != null) {
|
if (request.newsessionid != null) {
|
||||||
String domain = defaultCookie == null ? null : defaultCookie.getDomain();
|
String domain = defaultCookie == null ? null : defaultCookie.getDomain();
|
||||||
if (domain == null) {
|
if (domain == null || domain.isEmpty()) {
|
||||||
domain = "";
|
domain = "";
|
||||||
} else {
|
} else {
|
||||||
domain = "Domain=" + domain + "; ";
|
domain = "Domain=" + domain + "; ";
|
||||||
@@ -949,9 +949,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
String path = defaultCookie == null ? null : defaultCookie.getPath();
|
String path = defaultCookie == null ? null : defaultCookie.getPath();
|
||||||
if (path == null || path.isEmpty()) path = "/";
|
if (path == null || path.isEmpty()) path = "/";
|
||||||
if (request.newsessionid.isEmpty()) {
|
if (request.newsessionid.isEmpty()) {
|
||||||
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=" + path + "; Max-Age=0; HttpOnly\r\n").getBytes());
|
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=/; Max-Age=0; HttpOnly\r\n").getBytes());
|
||||||
} else {
|
} else {
|
||||||
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=" + path + "; HttpOnly\r\n").getBytes());
|
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=/; HttpOnly\r\n").getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.cookies != null) {
|
if (this.cookies != null) {
|
||||||
|
|||||||
@@ -375,6 +375,10 @@ public final class Rest {
|
|||||||
pushInt(mv, rws.wsmaxbody());
|
pushInt(mv, rws.wsmaxbody());
|
||||||
mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I");
|
mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I");
|
||||||
|
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
mv.visitInsn(rws.mergemsg() ? ICONST_1 : ICONST_0);
|
||||||
|
mv.visitFieldInsn(PUTFIELD, newDynName, "mergemsg", "Z");
|
||||||
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0);
|
mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0);
|
||||||
mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z");
|
mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z");
|
||||||
@@ -728,7 +732,13 @@ public final class Rest {
|
|||||||
final RestService controller = serviceType.getAnnotation(RestService.class);
|
final RestService controller = serviceType.getAnnotation(RestService.class);
|
||||||
if (controller != null && controller.ignore()) throw new RuntimeException(serviceType + " is ignore Rest Service Class"); //标记为ignore=true不创建Servlet
|
if (controller != null && controller.ignore()) throw new RuntimeException(serviceType + " is ignore Rest Service Class"); //标记为ignore=true不创建Servlet
|
||||||
ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
|
ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
|
||||||
String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet";
|
String stname = serviceType.getSimpleName();
|
||||||
|
if (stname.startsWith("Service")) { //类似ServiceWatchService这样的类保留第一个Service字样
|
||||||
|
stname = "Service" + stname.substring("Service".length()).replaceAll("Service.*$", "");
|
||||||
|
} else {
|
||||||
|
stname = stname.replaceAll("Service.*$", "");
|
||||||
|
}
|
||||||
|
String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + "_Dyn" + stname + "RestServlet";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
final String defmodulename = getWebModuleNameLowerCase(serviceType);
|
final String defmodulename = getWebModuleNameLowerCase(serviceType);
|
||||||
|
|||||||
@@ -60,6 +60,13 @@ public @interface RestWebSocket {
|
|||||||
*/
|
*/
|
||||||
boolean anyuser() default false;
|
boolean anyuser() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收客户端的分包(last=false)消息时是否自动合并包
|
||||||
|
*
|
||||||
|
* @return 默认true
|
||||||
|
*/
|
||||||
|
boolean mergemsg() default true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebScoket服务器给客户端进行ping操作的间隔时间, 单位: 秒, 默认值:15秒
|
* WebScoket服务器给客户端进行ping操作的间隔时间, 单位: 秒, 默认值:15秒
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -540,7 +540,7 @@ public abstract class WebSocket<G extends Serializable, T> {
|
|||||||
*/
|
*/
|
||||||
public CompletableFuture<Void> changeUserid(final G newuserid) {
|
public CompletableFuture<Void> changeUserid(final G newuserid) {
|
||||||
if (newuserid == null) throw new NullPointerException("newuserid is null");
|
if (newuserid == null) throw new NullPointerException("newuserid is null");
|
||||||
return _engine.changeUserid(this, newuserid);
|
return _engine.changeLocalUserid(this, newuserid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -558,26 +558,26 @@ public abstract class WebSocket<G extends Serializable, T> {
|
|||||||
/**
|
/**
|
||||||
* 获取当前WebSocket下的属性,非线程安全
|
* 获取当前WebSocket下的属性,非线程安全
|
||||||
*
|
*
|
||||||
* @param <T> 属性值的类型
|
* @param <V> 属性值的类型
|
||||||
* @param name 属性名
|
* @param name 属性名
|
||||||
*
|
*
|
||||||
* @return 属性值
|
* @return 属性值
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final <T> T getAttribute(String name) {
|
public final <V> V getAttribute(String name) {
|
||||||
return attributes == null ? null : (T) attributes.get(name);
|
return attributes == null ? null : (V) attributes.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移出当前WebSocket下的属性,非线程安全
|
* 移出当前WebSocket下的属性,非线程安全
|
||||||
*
|
*
|
||||||
* @param <T> 属性值的类型
|
* @param <V> 属性值的类型
|
||||||
* @param name 属性名
|
* @param name 属性名
|
||||||
*
|
*
|
||||||
* @return 属性值
|
* @return 属性值
|
||||||
*/
|
*/
|
||||||
public final <T> T removeAttribute(String name) {
|
public final <V> V removeAttribute(String name) {
|
||||||
return attributes == null ? null : (T) attributes.remove(name);
|
return attributes == null ? null : (V) attributes.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -76,11 +76,14 @@ public class WebSocketEngine {
|
|||||||
@Comment("最大消息体长度, 小于1表示无限制")
|
@Comment("最大消息体长度, 小于1表示无限制")
|
||||||
protected int wsmaxbody;
|
protected int wsmaxbody;
|
||||||
|
|
||||||
|
@Comment("接收客户端的分包(last=false)消息时是否自动合并包")
|
||||||
|
protected boolean mergemsg = true;
|
||||||
|
|
||||||
@Comment("加密解密器")
|
@Comment("加密解密器")
|
||||||
protected Cryptor cryptor;
|
protected Cryptor cryptor;
|
||||||
|
|
||||||
protected WebSocketEngine(String engineid, boolean single, HttpContext context, int liveinterval,
|
protected WebSocketEngine(String engineid, boolean single, HttpContext context, int liveinterval, int wsmaxconns,
|
||||||
int wsmaxconns, int wsthreads, int wsmaxbody, Cryptor cryptor, WebSocketNode node, Convert sendConvert, Logger logger) {
|
int wsthreads, int wsmaxbody, boolean mergemsg, Cryptor cryptor, WebSocketNode node, Convert sendConvert, Logger logger) {
|
||||||
this.engineid = engineid;
|
this.engineid = engineid;
|
||||||
this.single = single;
|
this.single = single;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -90,6 +93,7 @@ public class WebSocketEngine {
|
|||||||
this.wsmaxconns = wsmaxconns;
|
this.wsmaxconns = wsmaxconns;
|
||||||
this.wsthreads = wsthreads;
|
this.wsthreads = wsthreads;
|
||||||
this.wsmaxbody = wsmaxbody;
|
this.wsmaxbody = wsmaxbody;
|
||||||
|
this.mergemsg = mergemsg;
|
||||||
this.cryptor = cryptor;
|
this.cryptor = cryptor;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.index = sequence.getAndIncrement();
|
this.index = sequence.getAndIncrement();
|
||||||
@@ -127,7 +131,7 @@ public class WebSocketEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Comment("添加WebSocket")
|
@Comment("添加WebSocket")
|
||||||
void add(WebSocket socket) {
|
CompletableFuture<Void> addLocal(WebSocket socket) {
|
||||||
if (single) {
|
if (single) {
|
||||||
currconns.incrementAndGet();
|
currconns.incrementAndGet();
|
||||||
websockets.put(socket._userid, socket);
|
websockets.put(socket._userid, socket);
|
||||||
@@ -140,11 +144,12 @@ public class WebSocketEngine {
|
|||||||
currconns.incrementAndGet();
|
currconns.incrementAndGet();
|
||||||
list.add(socket);
|
list.add(socket);
|
||||||
}
|
}
|
||||||
if (node != null) node.connect(socket._userid);
|
if (node != null) return node.connect(socket._userid);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Comment("从WebSocketEngine删除指定WebSocket")
|
@Comment("从WebSocketEngine删除指定WebSocket")
|
||||||
CompletableFuture<Void> removeThenClose(WebSocket socket) {
|
CompletableFuture<Void> removeLocalThenClose(WebSocket socket) {
|
||||||
Serializable userid = socket._userid;
|
Serializable userid = socket._userid;
|
||||||
if (single) {
|
if (single) {
|
||||||
currconns.decrementAndGet();
|
currconns.decrementAndGet();
|
||||||
@@ -165,7 +170,7 @@ public class WebSocketEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Comment("更改WebSocket的userid")
|
@Comment("更改WebSocket的userid")
|
||||||
CompletableFuture<Void> changeUserid(WebSocket socket, final Serializable newuserid) {
|
CompletableFuture<Void> changeLocalUserid(WebSocket socket, final Serializable newuserid) {
|
||||||
if (newuserid == null) throw new NullPointerException("newuserid is null");
|
if (newuserid == null) throw new NullPointerException("newuserid is null");
|
||||||
final Serializable olduserid = socket._userid;
|
final Serializable olduserid = socket._userid;
|
||||||
socket._userid = newuserid;
|
socket._userid = newuserid;
|
||||||
@@ -207,20 +212,20 @@ public class WebSocketEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给所有连接用户发送消息")
|
@Comment("给所有连接用户发送消息")
|
||||||
public CompletableFuture<Integer> broadcastMessage(final Object message, final boolean last) {
|
public CompletableFuture<Integer> broadcastLocalMessage(final Object message, final boolean last) {
|
||||||
return broadcastMessage((Predicate) null, message, last);
|
return WebSocketEngine.this.broadcastLocalMessage((Predicate) null, message, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给指定WebSocket连接用户发送消息")
|
@Comment("给指定WebSocket连接用户发送消息")
|
||||||
public CompletableFuture<Integer> broadcastMessage(final WebSocketRange wsrange, final Object message, final boolean last) {
|
public CompletableFuture<Integer> broadcastLocalMessage(final WebSocketRange wsrange, final Object message, final boolean last) {
|
||||||
Predicate<WebSocket> predicate = wsrange == null ? null : (ws) -> ws.predicate(wsrange);
|
Predicate<WebSocket> predicate = wsrange == null ? null : (ws) -> ws.predicate(wsrange);
|
||||||
return broadcastMessage(predicate, message, last);
|
return WebSocketEngine.this.broadcastLocalMessage(predicate, message, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给指定WebSocket连接用户发送消息")
|
@Comment("给指定WebSocket连接用户发送消息")
|
||||||
public CompletableFuture<Integer> broadcastMessage(final Predicate<WebSocket> predicate, final Object message, final boolean last) {
|
public CompletableFuture<Integer> broadcastLocalMessage(final Predicate<WebSocket> predicate, final Object message, final boolean last) {
|
||||||
if (message instanceof CompletableFuture) {
|
if (message instanceof CompletableFuture) {
|
||||||
return ((CompletableFuture) message).thenCompose((json) -> broadcastMessage(predicate, json, last));
|
return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.broadcastLocalMessage(predicate, json, last));
|
||||||
}
|
}
|
||||||
final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null);
|
final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null);
|
||||||
if (more) {
|
if (more) {
|
||||||
@@ -265,19 +270,19 @@ public class WebSocketEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给指定用户组发送消息")
|
@Comment("给指定用户组发送消息")
|
||||||
public CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Stream<? extends Serializable> userids) {
|
public CompletableFuture<Integer> sendLocalMessage(final Object message, final boolean last, final Stream<? extends Serializable> userids) {
|
||||||
Object[] array = userids.toArray();
|
Object[] array = userids.toArray();
|
||||||
Serializable[] ss = new Serializable[array.length];
|
Serializable[] ss = new Serializable[array.length];
|
||||||
for (int i = 0; i < array.length; i++) {
|
for (int i = 0; i < array.length; i++) {
|
||||||
ss[i] = (Serializable) array[i];
|
ss[i] = (Serializable) array[i];
|
||||||
}
|
}
|
||||||
return sendMessage(message, last, ss);
|
return WebSocketEngine.this.sendLocalMessage(message, last, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给指定用户组发送消息")
|
@Comment("给指定用户组发送消息")
|
||||||
public CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Serializable... userids) {
|
public CompletableFuture<Integer> sendLocalMessage(final Object message, final boolean last, final Serializable... userids) {
|
||||||
if (message instanceof CompletableFuture) {
|
if (message instanceof CompletableFuture) {
|
||||||
return ((CompletableFuture) message).thenCompose((json) -> sendMessage(json, last, userids));
|
return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.sendLocalMessage(json, last, userids));
|
||||||
}
|
}
|
||||||
final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null) && userids.length > 1;
|
final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null) && userids.length > 1;
|
||||||
if (more) {
|
if (more) {
|
||||||
@@ -326,7 +331,7 @@ public class WebSocketEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给指定WebSocket连接用户发起操作指令")
|
@Comment("给指定WebSocket连接用户发起操作指令")
|
||||||
public CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
|
public CompletableFuture<Integer> broadcastLocalAction(final WebSocketAction action) {
|
||||||
CompletableFuture<Integer> future = null;
|
CompletableFuture<Integer> future = null;
|
||||||
if (single) {
|
if (single) {
|
||||||
for (WebSocket websocket : websockets.values()) {
|
for (WebSocket websocket : websockets.values()) {
|
||||||
@@ -343,17 +348,17 @@ public class WebSocketEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给指定用户组发送操作")
|
@Comment("给指定用户组发送操作")
|
||||||
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Stream<? extends Serializable> userids) {
|
public CompletableFuture<Integer> sendLocalAction(final WebSocketAction action, final Stream<? extends Serializable> userids) {
|
||||||
Object[] array = userids.toArray();
|
Object[] array = userids.toArray();
|
||||||
Serializable[] ss = new Serializable[array.length];
|
Serializable[] ss = new Serializable[array.length];
|
||||||
for (int i = 0; i < array.length; i++) {
|
for (int i = 0; i < array.length; i++) {
|
||||||
ss[i] = (Serializable) array[i];
|
ss[i] = (Serializable) array[i];
|
||||||
}
|
}
|
||||||
return sendAction(action, ss);
|
return WebSocketEngine.this.sendLocalAction(action, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Comment("给指定用户组发送操作")
|
@Comment("给指定用户组发送操作")
|
||||||
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
|
public CompletableFuture<Integer> sendLocalAction(final WebSocketAction action, final Serializable... userids) {
|
||||||
CompletableFuture<Integer> future = null;
|
CompletableFuture<Integer> future = null;
|
||||||
if (single) {
|
if (single) {
|
||||||
for (Serializable userid : userids) {
|
for (Serializable userid : userids) {
|
||||||
|
|||||||
@@ -59,7 +59,11 @@ public abstract class WebSocketNode {
|
|||||||
|
|
||||||
protected Semaphore semaphore;
|
protected Semaphore semaphore;
|
||||||
|
|
||||||
|
private int tryAcquireSeconds = 12;
|
||||||
|
|
||||||
public void init(AnyValue conf) {
|
public void init(AnyValue conf) {
|
||||||
|
this.tryAcquireSeconds = Integer.getInteger("WebSocketNode.tryAcquireSeconds", 12);
|
||||||
|
|
||||||
if (sncpNodeAddresses != null && "memory".equals(sncpNodeAddresses.getType())) {
|
if (sncpNodeAddresses != null && "memory".equals(sncpNodeAddresses.getType())) {
|
||||||
sncpNodeAddresses.initValueType(InetSocketAddress.class);
|
sncpNodeAddresses.initValueType(InetSocketAddress.class);
|
||||||
}
|
}
|
||||||
@@ -79,7 +83,7 @@ public abstract class WebSocketNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Local
|
@Local
|
||||||
public final void postDestroy(AnyValue conf) {
|
protected void postDestroy(AnyValue conf) {
|
||||||
if (this.localEngine == null) return;
|
if (this.localEngine == null) return;
|
||||||
//关掉所有本地本地WebSocket
|
//关掉所有本地本地WebSocket
|
||||||
this.localEngine.getLocalWebSockets().forEach(g -> g.close());
|
this.localEngine.getLocalWebSockets().forEach(g -> g.close());
|
||||||
@@ -90,11 +94,11 @@ public abstract class WebSocketNode {
|
|||||||
|
|
||||||
protected abstract CompletableFuture<List<String>> getWebSocketAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable userid);
|
protected abstract CompletableFuture<List<String>> getWebSocketAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable userid);
|
||||||
|
|
||||||
protected abstract CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable userid);
|
protected abstract CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids);
|
||||||
|
|
||||||
protected abstract CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketRange wsrange, Object message, boolean last);
|
protected abstract CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketRange wsrange, Object message, boolean last);
|
||||||
|
|
||||||
protected abstract CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action, Serializable userid);
|
protected abstract CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action, Serializable... userids);
|
||||||
|
|
||||||
protected abstract CompletableFuture<Integer> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action);
|
protected abstract CompletableFuture<Integer> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action);
|
||||||
|
|
||||||
@@ -204,25 +208,6 @@ public abstract class WebSocketNode {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*
|
|
||||||
* 判断指定用户是否WebSocket在线
|
|
||||||
*
|
|
||||||
* @param userid Serializable
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
private CompletableFuture<Boolean> existsWebSocket2(final Serializable userid) {
|
|
||||||
if (this.localEngine != null && this.sncpNodeAddresses == null) {
|
|
||||||
return CompletableFuture.completedFuture(this.localEngine.existsLocalWebSocket(userid));
|
|
||||||
}
|
|
||||||
tryAcquireSemaphore();
|
|
||||||
CompletableFuture<Boolean> rs = this.sncpNodeAddresses.existsAsync(SOURCE_SNCP_USERID_PREFIX + userid);
|
|
||||||
if (semaphore != null) rs.whenComplete((r, e) -> releaseSemaphore());
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断指定用户是否WebSocket在线
|
* 判断指定用户是否WebSocket在线
|
||||||
*
|
*
|
||||||
@@ -429,15 +414,97 @@ public abstract class WebSocketNode {
|
|||||||
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(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), 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.sncpNodeAddresses == null) { //本地模式且没有分布式
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
return this.localEngine.sendMessage(message, last, userids);
|
return this.localEngine.sendLocalMessage(message, last, userids);
|
||||||
}
|
}
|
||||||
final Object remoteMessage = formatRemoteMessage(message);
|
final Object remoteMessage = formatRemoteMessage(message);
|
||||||
CompletableFuture<Integer> future = null;
|
CompletableFuture<Integer> rsfuture;
|
||||||
for (Serializable userid : userids) {
|
if (userids.length == 1) {
|
||||||
future = future == null ? sendOneMessage(remoteMessage, last, userid)
|
rsfuture = sendOneUserMessage(remoteMessage, last, userids[0]);
|
||||||
: future.thenCombine(sendOneMessage(remoteMessage, last, userid), (a, b) -> a | b);
|
} else {
|
||||||
|
String[] keys = new String[userids.length];
|
||||||
|
final Map<String, Serializable> keyuser = new HashMap<>();
|
||||||
|
for (int i = 0; i < userids.length; i++) {
|
||||||
|
keys[i] = SOURCE_SNCP_USERID_PREFIX + userids[i];
|
||||||
|
keyuser.put(keys[i], userids[i]);
|
||||||
|
}
|
||||||
|
tryAcquireSemaphore();
|
||||||
|
CompletableFuture<Map<String, Collection<InetSocketAddress>>> addrsFuture = sncpNodeAddresses.getCollectionMapAsync(InetSocketAddress.class, keys);
|
||||||
|
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
||||||
|
rsfuture = addrsFuture.thenCompose((Map<String, Collection<InetSocketAddress>> addrs) -> {
|
||||||
|
if (addrs == null || addrs.isEmpty()) {
|
||||||
|
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<InetSocketAddress, List<Serializable>> addrUsers = new HashMap<>();
|
||||||
|
addrs.forEach((key, as) -> {
|
||||||
|
for (InetSocketAddress a : as) {
|
||||||
|
addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found message-addr-userids: " + addrUsers);
|
||||||
|
}
|
||||||
|
CompletableFuture<Integer> future = null;
|
||||||
|
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
||||||
|
Serializable[] us = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
||||||
|
future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, us)
|
||||||
|
: future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, us), (a, b) -> a | b);
|
||||||
|
}
|
||||||
|
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.finest("websocket want send message {userid:" + userid + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : 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.sncpNodeAddresses == null || this.remoteNode == null) {
|
||||||
|
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
||||||
|
//没有CacheSource就不会有分布式节点
|
||||||
|
return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture;
|
||||||
|
}
|
||||||
|
//远程节点发送消息
|
||||||
|
final Object remoteMessage = formatRemoteMessage(message);
|
||||||
|
tryAcquireSemaphore();
|
||||||
|
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
|
||||||
|
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
||||||
|
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
|
||||||
|
if (addrs == null || addrs.isEmpty()) {
|
||||||
|
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);
|
||||||
|
CompletableFuture<Integer> future = null;
|
||||||
|
for (InetSocketAddress addr : addrs) {
|
||||||
|
if (addr == null || addr.equals(localSncpAddress)) continue;
|
||||||
|
future = future == null ? remoteNode.sendMessage(addr, remoteMessage, last, userid)
|
||||||
|
: future.thenCombine(remoteNode.sendMessage(addr, remoteMessage, last, userid), (a, b) -> a | b);
|
||||||
|
}
|
||||||
|
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
||||||
|
});
|
||||||
|
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CompletableFuture<Integer> sendOneAddrMessage(final InetSocketAddress sncpAddr, final Object message, final boolean last, final Serializable... userids) {
|
||||||
|
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(sncpAddr, msg, last, userids));
|
||||||
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||||
|
}
|
||||||
|
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
|
||||||
|
return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids);
|
||||||
|
}
|
||||||
|
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
||||||
|
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
||||||
|
//没有CacheSource就不会有分布式节点
|
||||||
|
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
|
}
|
||||||
|
final Object remoteMessage = formatRemoteMessage(message);
|
||||||
|
return remoteNode.sendMessage(sncpAddr, remoteMessage, last, userids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -548,10 +615,10 @@ public abstract class WebSocketNode {
|
|||||||
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));
|
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.sncpNodeAddresses == null) { //本地模式且没有分布式
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
return this.localEngine.broadcastMessage(wsrange, message, last);
|
return this.localEngine.broadcastLocalMessage(wsrange, message, last);
|
||||||
}
|
}
|
||||||
final Object remoteMessage = formatRemoteMessage(message);
|
final Object remoteMessage = formatRemoteMessage(message);
|
||||||
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastMessage(wsrange, message, last);
|
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalMessage(wsrange, message, last);
|
||||||
tryAcquireSemaphore();
|
tryAcquireSemaphore();
|
||||||
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class);
|
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class);
|
||||||
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
||||||
@@ -569,40 +636,6 @@ public abstract class WebSocketNode {
|
|||||||
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CompletableFuture<Integer> sendOneMessage(final Object message, final boolean last, final Serializable userid) {
|
|
||||||
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneMessage(msg, last, userid));
|
|
||||||
if (logger.isLoggable(Level.FINEST)) {
|
|
||||||
logger.finest("websocket want send message {userid:" + userid + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
|
||||||
}
|
|
||||||
CompletableFuture<Integer> localFuture = null;
|
|
||||||
if (this.localEngine != null) localFuture = localEngine.sendMessage(message, last, userid);
|
|
||||||
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
|
||||||
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
|
||||||
//没有CacheSource就不会有分布式节点
|
|
||||||
return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture;
|
|
||||||
}
|
|
||||||
//远程节点发送消息
|
|
||||||
final Object remoteMessage = formatRemoteMessage(message);
|
|
||||||
tryAcquireSemaphore();
|
|
||||||
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
|
|
||||||
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
|
||||||
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
|
|
||||||
if (addrs == null || addrs.isEmpty()) {
|
|
||||||
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);
|
|
||||||
CompletableFuture<Integer> future = null;
|
|
||||||
for (InetSocketAddress addr : addrs) {
|
|
||||||
if (addr == null || addr.equals(localSncpAddress)) continue;
|
|
||||||
future = future == null ? remoteNode.sendMessage(addr, remoteMessage, last, userid)
|
|
||||||
: future.thenCombine(remoteNode.sendMessage(addr, remoteMessage, last, userid), (a, b) -> a | b);
|
|
||||||
}
|
|
||||||
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
|
||||||
});
|
|
||||||
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 广播操作, 给所有人发操作
|
* 广播操作, 给所有人发操作
|
||||||
*
|
*
|
||||||
@@ -613,9 +646,9 @@ public abstract class WebSocketNode {
|
|||||||
@Local
|
@Local
|
||||||
public CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
|
public CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
|
||||||
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
return this.localEngine.broadcastAction(action);
|
return this.localEngine.broadcastLocalAction(action);
|
||||||
}
|
}
|
||||||
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastAction(action);
|
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalAction(action);
|
||||||
tryAcquireSemaphore();
|
tryAcquireSemaphore();
|
||||||
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class);
|
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class);
|
||||||
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
||||||
@@ -646,21 +679,53 @@ public abstract class WebSocketNode {
|
|||||||
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
|
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 (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
return this.localEngine.sendAction(action, userids);
|
return this.localEngine.sendLocalAction(action, userids);
|
||||||
}
|
}
|
||||||
CompletableFuture<Integer> future = null;
|
CompletableFuture<Integer> rsfuture;
|
||||||
for (Serializable userid : userids) {
|
if (userids.length == 1) {
|
||||||
future = future == null ? sendOneAction(action, userid) : future.thenCombine(sendOneAction(action, userid), (a, b) -> a | b);
|
rsfuture = sendOneUserAction(action, userids[0]);
|
||||||
|
} else {
|
||||||
|
String[] keys = new String[userids.length];
|
||||||
|
final Map<String, Serializable> keyuser = new HashMap<>();
|
||||||
|
for (int i = 0; i < userids.length; i++) {
|
||||||
|
keys[i] = SOURCE_SNCP_USERID_PREFIX + userids[i];
|
||||||
|
keyuser.put(keys[i], userids[i]);
|
||||||
|
}
|
||||||
|
tryAcquireSemaphore();
|
||||||
|
CompletableFuture<Map<String, Collection<InetSocketAddress>>> addrsFuture = sncpNodeAddresses.getCollectionMapAsync(InetSocketAddress.class, keys);
|
||||||
|
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
||||||
|
rsfuture = addrsFuture.thenCompose((Map<String, Collection<InetSocketAddress>> addrs) -> {
|
||||||
|
if (addrs == null || addrs.isEmpty()) {
|
||||||
|
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<InetSocketAddress, List<Serializable>> addrUsers = new HashMap<>();
|
||||||
|
addrs.forEach((key, as) -> {
|
||||||
|
for (InetSocketAddress a : as) {
|
||||||
|
addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found action-userid-addrs: " + addrUsers);
|
||||||
|
}
|
||||||
|
CompletableFuture<Integer> future = null;
|
||||||
|
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
||||||
|
Serializable[] us = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
||||||
|
future = future == null ? sendOneAddrAction(en.getKey(), action, us)
|
||||||
|
: future.thenCombine(sendOneAddrAction(en.getKey(), action, us), (a, b) -> a | b);
|
||||||
|
}
|
||||||
|
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CompletableFuture<Integer> sendOneAction(final WebSocketAction action, final Serializable userid) {
|
protected CompletableFuture<Integer> sendOneUserAction(final WebSocketAction action, final Serializable userid) {
|
||||||
if (logger.isLoggable(Level.FINEST)) {
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||||
}
|
}
|
||||||
CompletableFuture<Integer> localFuture = null;
|
CompletableFuture<Integer> localFuture = null;
|
||||||
if (this.localEngine != null) localFuture = localEngine.sendAction(action, userid);
|
if (this.localEngine != null) localFuture = localEngine.sendLocalAction(action, userid);
|
||||||
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
||||||
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
||||||
//没有CacheSource就不会有分布式节点
|
//没有CacheSource就不会有分布式节点
|
||||||
@@ -687,6 +752,21 @@ public abstract class WebSocketNode {
|
|||||||
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected CompletableFuture<Integer> sendOneAddrAction(final InetSocketAddress sncpAddr, final WebSocketAction action, final Serializable... userids) {
|
||||||
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.finest("websocket want send action {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", action:" + action + " from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||||
|
}
|
||||||
|
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
|
||||||
|
return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalAction(action, userids);
|
||||||
|
}
|
||||||
|
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
||||||
|
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
||||||
|
//没有CacheSource就不会有分布式节点
|
||||||
|
return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
|
}
|
||||||
|
return remoteNode.sendAction(sncpAddr, action, userids);
|
||||||
|
}
|
||||||
|
|
||||||
protected Object formatRemoteMessage(Object message) {
|
protected Object formatRemoteMessage(Object message) {
|
||||||
if (message instanceof WebSocketPacket) return message;
|
if (message instanceof WebSocketPacket) return message;
|
||||||
if (message instanceof byte[]) return message;
|
if (message instanceof byte[]) return message;
|
||||||
@@ -699,7 +779,7 @@ public abstract class WebSocketNode {
|
|||||||
protected boolean tryAcquireSemaphore() {
|
protected boolean tryAcquireSemaphore() {
|
||||||
if (this.semaphore == null) return true;
|
if (this.semaphore == null) return true;
|
||||||
try {
|
try {
|
||||||
return this.semaphore.tryAcquire(6, TimeUnit.SECONDS);
|
return this.semaphore.tryAcquire(tryAcquireSeconds, TimeUnit.SECONDS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.util.function.*;
|
|||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.net.Cryptor;
|
import org.redkale.net.Cryptor;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -24,6 +25,8 @@ import org.redkale.net.Cryptor;
|
|||||||
*/
|
*/
|
||||||
public final class WebSocketPacket {
|
public final class WebSocketPacket {
|
||||||
|
|
||||||
|
public static final Object MESSAGE_NIL = new Object();
|
||||||
|
|
||||||
static final WebSocketPacket NONE = new WebSocketPacket();
|
static final WebSocketPacket NONE = new WebSocketPacket();
|
||||||
|
|
||||||
public static final WebSocketPacket DEFAULT_PING_PACKET = new WebSocketPacket(FrameType.PING, new byte[0]);
|
public static final WebSocketPacket DEFAULT_PING_PACKET = new WebSocketPacket(FrameType.PING, new byte[0]);
|
||||||
@@ -34,7 +37,7 @@ public final class WebSocketPacket {
|
|||||||
|
|
||||||
public static enum FrameType {
|
public static enum FrameType {
|
||||||
|
|
||||||
TEXT(0x01), BINARY(0x02), CLOSE(0x08), PING(0x09), PONG(0x0A);
|
SERIES(0x00), TEXT(0x01), BINARY(0x02), CLOSE(0x08), PING(0x09), PONG(0x0A);
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
|
|
||||||
@@ -48,6 +51,7 @@ public final class WebSocketPacket {
|
|||||||
|
|
||||||
public static FrameType valueOf(int v) {
|
public static FrameType valueOf(int v) {
|
||||||
switch (v) {
|
switch (v) {
|
||||||
|
case 0x00: return SERIES;
|
||||||
case 0x01: return TEXT;
|
case 0x01: return TEXT;
|
||||||
case 0x02: return BINARY;
|
case 0x02: return BINARY;
|
||||||
case 0x08: return CLOSE;
|
case 0x08: return CLOSE;
|
||||||
@@ -344,11 +348,19 @@ public final class WebSocketPacket {
|
|||||||
*
|
*
|
||||||
* @return boolean 已接收完返回true, 需要继续接收body返回false;
|
* @return boolean 已接收完返回true, 需要继续接收body返回false;
|
||||||
*/
|
*/
|
||||||
boolean receiveBody(WebSocket webSocket, ByteBuffer readBuffer) {
|
boolean receiveBody(final Logger logger, WebSocketRunner runner, WebSocket webSocket, ByteBuffer readBuffer) {
|
||||||
|
final boolean debug = false; //调试开关
|
||||||
int need = receiveLength - receiveCount;
|
int need = receiveLength - receiveCount;
|
||||||
boolean over = readBuffer.remaining() >= need;
|
final int remain = readBuffer.remaining();
|
||||||
|
boolean over = remain >= need;
|
||||||
this.receiveBuffers = Utility.append(this.receiveBuffers, readBuffer);
|
this.receiveBuffers = Utility.append(this.receiveBuffers, readBuffer);
|
||||||
if (over) parseReceiveMessage(webSocket, this.receiveBuffers);
|
if (debug) logger.finest("receiveBody: receiveLength=" + receiveLength + ", this.receiveCount=" + this.receiveCount + ", readBuffer=" + remain);
|
||||||
|
if (over) {
|
||||||
|
this.receiveCount = this.receiveLength;
|
||||||
|
parseReceiveMessage(logger, runner, webSocket, this.receiveBuffers);
|
||||||
|
} else {
|
||||||
|
this.receiveCount += remain;
|
||||||
|
}
|
||||||
return over;
|
return over;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +391,7 @@ public final class WebSocketPacket {
|
|||||||
*
|
*
|
||||||
* @return 返回NONE表示Buffer内容不够; 返回this表示解析完成或部分解析完成;返回null表示解析异常;
|
* @return 返回NONE表示Buffer内容不够; 返回this表示解析完成或部分解析完成;返回null表示解析异常;
|
||||||
*/
|
*/
|
||||||
WebSocketPacket decode(final Logger logger, final WebSocket webSocket, final int wsmaxbody,
|
WebSocketPacket decode(final Logger logger, final WebSocketRunner runner, final WebSocket webSocket, final int wsmaxbody,
|
||||||
final AbstractMap.SimpleEntry<String, byte[]> halfBytes, final ByteBuffer buffer) {
|
final AbstractMap.SimpleEntry<String, byte[]> halfBytes, final ByteBuffer buffer) {
|
||||||
//开始
|
//开始
|
||||||
final boolean debug = false; //调试开关
|
final boolean debug = false; //调试开关
|
||||||
@@ -394,9 +406,13 @@ public final class WebSocketPacket {
|
|||||||
final byte opcode = buffer.get(); //第一个字节
|
final byte opcode = buffer.get(); //第一个字节
|
||||||
this.last = (opcode & 0b1000_0000) != 0;
|
this.last = (opcode & 0b1000_0000) != 0;
|
||||||
this.type = FrameType.valueOf(opcode & 0xF);
|
this.type = FrameType.valueOf(opcode & 0xF);
|
||||||
|
|
||||||
if (type == FrameType.CLOSE) {
|
if (type == FrameType.CLOSE) {
|
||||||
if (debug) logger.log(Level.FINEST, " receive close command from websocket client");
|
if (debug) logger.log(Level.FINEST, " receive close command from websocket client");
|
||||||
}
|
}
|
||||||
|
if (type == null) {
|
||||||
|
logger.log(Level.SEVERE, " receive unknown frametype(opcode=" + (opcode & 0xF) + ") from websocket client");
|
||||||
|
}
|
||||||
final boolean checkrsv = false;//暂时不校验
|
final boolean checkrsv = false;//暂时不校验
|
||||||
if (checkrsv && (opcode & 0b0111_0000) != 0) {
|
if (checkrsv && (opcode & 0b0111_0000) != 0) {
|
||||||
if (debug) logger.log(Level.FINE, "rsv1 rsv2 rsv3 must be 0, but not (" + opcode + ")");
|
if (debug) logger.log(Level.FINE, "rsv1 rsv2 rsv3 must be 0, but not (" + opcode + ")");
|
||||||
@@ -438,15 +454,18 @@ public final class WebSocketPacket {
|
|||||||
}
|
}
|
||||||
if (lengthCode == 0x7E) {//0x7E=126
|
if (lengthCode == 0x7E) {//0x7E=126
|
||||||
length = (int) buffer.getChar();
|
length = (int) buffer.getChar();
|
||||||
|
} else if (lengthCode == 0x7F) {//0x7E=127
|
||||||
|
length = (int) buffer.getLong();
|
||||||
} else {
|
} else {
|
||||||
length = buffer.getInt();
|
length = buffer.getInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (length > wsmaxbody && wsmaxbody > 0) {
|
if (length > wsmaxbody && wsmaxbody > 0) {
|
||||||
if (debug) logger.log(Level.FINE, "message length (" + length + ") too big, must less " + wsmaxbody + "");
|
logger.log(Level.WARNING, "message length (" + length + ") too big, must less " + wsmaxbody + "");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
this.receiveLength = length;
|
this.receiveLength = length;
|
||||||
|
if (debug) logger.finest("this.receiveLength: " + length + ", code=" + lengthCode + ", last=" + last);
|
||||||
if (masked) {
|
if (masked) {
|
||||||
final byte[] masks = new byte[4];
|
final byte[] masks = new byte[4];
|
||||||
buffer.get(masks);
|
buffer.get(masks);
|
||||||
@@ -461,7 +480,7 @@ public final class WebSocketPacket {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (buffer.remaining() >= this.receiveLength) { //内容足够, 可以解析
|
if (buffer.remaining() >= this.receiveLength) { //内容足够, 可以解析
|
||||||
this.parseReceiveMessage(webSocket, buffer);
|
this.parseReceiveMessage(logger, runner, webSocket, buffer);
|
||||||
this.receiveCount = this.receiveLength;
|
this.receiveCount = this.receiveLength;
|
||||||
} else {
|
} else {
|
||||||
this.receiveCount = buffer.remaining();
|
this.receiveCount = buffer.remaining();
|
||||||
@@ -470,38 +489,77 @@ public final class WebSocketPacket {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseReceiveMessage(WebSocket webSocket, ByteBuffer... buffers) {
|
void parseReceiveMessage(final Logger logger, WebSocketRunner runner, WebSocket webSocket, ByteBuffer... buffers) {
|
||||||
if (webSocket._engine.cryptor != null) {
|
if (webSocket._engine.cryptor != null) {
|
||||||
HttpContext context = webSocket._engine.context;
|
HttpContext context = webSocket._engine.context;
|
||||||
buffers = webSocket._engine.cryptor.decrypt(buffers, context.getBufferSupplier(), context.getBufferConsumer());
|
buffers = webSocket._engine.cryptor.decrypt(buffers, context.getBufferSupplier(), context.getBufferConsumer());
|
||||||
}
|
}
|
||||||
if (this.type == FrameType.TEXT) {
|
FrameType selfType = this.type;
|
||||||
|
final boolean series = selfType == FrameType.SERIES;
|
||||||
|
if (series) {
|
||||||
|
selfType = runner.currSeriesMergeFrameType;
|
||||||
|
this.type = selfType;
|
||||||
|
} else if (!this.last && (selfType == FrameType.TEXT || selfType == FrameType.BINARY)) {
|
||||||
|
runner.currSeriesMergeFrameType = selfType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selfType == FrameType.TEXT) {
|
||||||
Convert textConvert = webSocket.getTextConvert();
|
Convert textConvert = webSocket.getTextConvert();
|
||||||
if (textConvert == null) {
|
if (textConvert == null || (!runner.mergemsg && (series || !this.last))) {
|
||||||
this.receiveMessage = new String(this.getReceiveBytes(buffers), StandardCharsets.UTF_8);
|
this.receiveMessage = new String(this.getReceiveBytes(buffers), StandardCharsets.UTF_8);
|
||||||
this.receiveType = MessageType.STRING;
|
this.receiveType = MessageType.STRING;
|
||||||
} else {
|
} else {
|
||||||
this.receiveMessage = textConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
|
if (this.last || !runner.mergemsg) {
|
||||||
|
if (runner.currSeriesMergeMessage == null) {
|
||||||
|
this.receiveMessage = textConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
|
||||||
|
} else {
|
||||||
|
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
|
||||||
|
try {
|
||||||
|
this.receiveMessage = textConvert.convertFrom(webSocket._messageTextType, runner.currSeriesMergeMessage.getBytes());
|
||||||
|
} finally {
|
||||||
|
runner.currSeriesMergeMessage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (runner.currSeriesMergeMessage == null) runner.currSeriesMergeMessage = new ByteArray();
|
||||||
|
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
|
||||||
|
this.receiveMessage = MESSAGE_NIL;
|
||||||
|
}
|
||||||
this.receiveCount = this.receiveLength;
|
this.receiveCount = this.receiveLength;
|
||||||
this.receiveType = MessageType.OBJECT;
|
this.receiveType = MessageType.OBJECT;
|
||||||
}
|
}
|
||||||
} else if (this.type == FrameType.BINARY) {
|
} else if (selfType == FrameType.BINARY) {
|
||||||
Convert binaryConvert = webSocket.getBinaryConvert();
|
Convert binaryConvert = webSocket.getBinaryConvert();
|
||||||
if (binaryConvert == null) {
|
if (binaryConvert == null || (!runner.mergemsg && (series || !this.last))) {
|
||||||
this.receiveMessage = this.getReceiveBytes(buffers);
|
this.receiveMessage = this.getReceiveBytes(buffers);
|
||||||
this.receiveType = MessageType.BYTES;
|
this.receiveType = MessageType.BYTES;
|
||||||
} else {
|
} else {
|
||||||
this.receiveMessage = binaryConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
|
if (this.last || !runner.mergemsg) {
|
||||||
|
if (runner.currSeriesMergeMessage == null) {
|
||||||
|
this.receiveMessage = binaryConvert.convertFrom(webSocket._messageTextType, this.receiveMasker, buffers);
|
||||||
|
} else {
|
||||||
|
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
|
||||||
|
try {
|
||||||
|
this.receiveMessage = binaryConvert.convertFrom(webSocket._messageTextType, runner.currSeriesMergeMessage.getBytes());
|
||||||
|
} finally {
|
||||||
|
runner.currSeriesMergeMessage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (runner.currSeriesMergeMessage == null) runner.currSeriesMergeMessage = new ByteArray();
|
||||||
|
runner.currSeriesMergeMessage.write(this.getReceiveBytes(buffers));
|
||||||
|
this.receiveMessage = MESSAGE_NIL;
|
||||||
|
}
|
||||||
this.receiveCount = this.receiveLength;
|
this.receiveCount = this.receiveLength;
|
||||||
this.receiveType = MessageType.OBJECT;
|
this.receiveType = MessageType.OBJECT;
|
||||||
}
|
}
|
||||||
} else if (this.type == FrameType.PING) {
|
} else if (selfType == FrameType.PING) {
|
||||||
this.receiveMessage = this.getReceiveBytes(buffers);
|
this.receiveMessage = this.getReceiveBytes(buffers);
|
||||||
this.receiveType = MessageType.BYTES;
|
this.receiveType = MessageType.BYTES;
|
||||||
} else if (this.type == FrameType.PONG) {
|
} else if (selfType == FrameType.PONG) {
|
||||||
this.receiveMessage = this.getReceiveBytes(buffers);
|
this.receiveMessage = this.getReceiveBytes(buffers);
|
||||||
this.receiveType = MessageType.BYTES;
|
this.receiveType = MessageType.BYTES;
|
||||||
} else if (this.type == FrameType.CLOSE) {
|
} else if (selfType == FrameType.CLOSE) {
|
||||||
this.receiveMessage = this.getReceiveBytes(buffers);
|
this.receiveMessage = this.getReceiveBytes(buffers);
|
||||||
this.receiveType = MessageType.BYTES;
|
this.receiveType = MessageType.BYTES;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.util.AbstractMap.SimpleEntry;
|
|||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
import org.redkale.util.ByteArray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebSocket的消息接收发送器, 一个WebSocket对应一个WebSocketRunner
|
* WebSocket的消息接收发送器, 一个WebSocket对应一个WebSocketRunner
|
||||||
@@ -34,10 +35,14 @@ class WebSocketRunner implements Runnable {
|
|||||||
|
|
||||||
protected final HttpContext context;
|
protected final HttpContext context;
|
||||||
|
|
||||||
private ByteBuffer readBuffer;
|
protected final boolean mergemsg;
|
||||||
|
|
||||||
volatile boolean closed = false;
|
volatile boolean closed = false;
|
||||||
|
|
||||||
|
FrameType currSeriesMergeFrameType;
|
||||||
|
|
||||||
|
ByteArray currSeriesMergeMessage;
|
||||||
|
|
||||||
private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用
|
private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用
|
||||||
|
|
||||||
protected long lastSendTime;
|
protected long lastSendTime;
|
||||||
@@ -48,20 +53,21 @@ class WebSocketRunner implements Runnable {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.engine = webSocket._engine;
|
this.engine = webSocket._engine;
|
||||||
this.webSocket = webSocket;
|
this.webSocket = webSocket;
|
||||||
|
this.mergemsg = webSocket._engine.mergemsg;
|
||||||
this.restMessageConsumer = messageConsumer;
|
this.restMessageConsumer = messageConsumer;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.readBuffer = context.pollBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final boolean debug = context.getLogger().isLoggable(Level.FINEST);
|
final boolean debug = context.getLogger().isLoggable(Level.FINEST);
|
||||||
|
final WebSocketRunner self = this;
|
||||||
try {
|
try {
|
||||||
webSocket.onConnected();
|
webSocket.onConnected();
|
||||||
channel.setReadTimeoutSeconds(300); //读取超时5分钟
|
channel.setReadTimeoutSeconds(300); //读取超时5分钟
|
||||||
if (channel.isOpen()) {
|
if (channel.isOpen()) {
|
||||||
final int wsmaxbody = webSocket._engine.wsmaxbody;
|
final int wsmaxbody = webSocket._engine.wsmaxbody;
|
||||||
channel.read(readBuffer, null, new CompletionHandler<Integer, Void>() {
|
channel.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
//尚未解析完的数据包
|
//尚未解析完的数据包
|
||||||
private WebSocketPacket unfinishPacket;
|
private WebSocketPacket unfinishPacket;
|
||||||
@@ -72,31 +78,27 @@ class WebSocketRunner implements Runnable {
|
|||||||
private final SimpleEntry<String, byte[]> halfBytes = new SimpleEntry("", null);
|
private final SimpleEntry<String, byte[]> halfBytes = new SimpleEntry("", null);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer count, Void attachment1) {
|
public void completed(Integer count, ByteBuffer readBuffer) {
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner(userid=" + webSocket.getUserid() + ") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner(userid=" + webSocket.getUserid() + ") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
||||||
closeRunner(CLOSECODE_ILLPACKET, "read buffer count is " + count);
|
closeRunner(CLOSECODE_ILLPACKET, "read buffer count is " + count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ByteBuffer readBuf = readBuffer;
|
|
||||||
if (readBuf == null) return; //关闭后readBuffer为null
|
|
||||||
lastReadTime = System.currentTimeMillis();
|
lastReadTime = System.currentTimeMillis();
|
||||||
readBuf.flip();
|
readBuffer.flip();
|
||||||
|
|
||||||
WebSocketPacket onePacket = null;
|
WebSocketPacket onePacket = null;
|
||||||
if (unfinishPacket != null) {
|
if (unfinishPacket != null) {
|
||||||
if (unfinishPacket.receiveBody(webSocket, readBuf)) { //已经接收完毕
|
if (unfinishPacket.receiveBody(context.getLogger(), self, webSocket, readBuffer)) { //已经接收完毕
|
||||||
onePacket = unfinishPacket;
|
onePacket = unfinishPacket;
|
||||||
unfinishPacket = null;
|
unfinishPacket = null;
|
||||||
for (ByteBuffer b : exBuffers) {
|
for (ByteBuffer b : exBuffers) {
|
||||||
context.offerBuffer(b);
|
context.offerBuffer(b);
|
||||||
}
|
}
|
||||||
exBuffers.clear();
|
exBuffers.clear();
|
||||||
} else { //需要继续接收
|
} else { //需要继续接收, 此处不能回收readBuffer
|
||||||
readBuf = context.pollBuffer();
|
channel.read(this);
|
||||||
readBuffer = readBuf;
|
|
||||||
channel.read(readBuf, null, this);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,39 +107,43 @@ class WebSocketRunner implements Runnable {
|
|||||||
if (onePacket != null) packets.add(onePacket);
|
if (onePacket != null) packets.add(onePacket);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
WebSocketPacket packet = new WebSocketPacket().decode(context.getLogger(), webSocket, wsmaxbody, halfBytes, readBuf);
|
WebSocketPacket packet = new WebSocketPacket().decode(context.getLogger(), self, webSocket, wsmaxbody, halfBytes, readBuffer);
|
||||||
if (packet == WebSocketPacket.NONE) break; //解析完毕但是buffer有多余字节
|
if (packet == WebSocketPacket.NONE) break; //解析完毕但是buffer有多余字节
|
||||||
if (packet != null && !packet.isReceiveFinished()) {
|
if (packet != null && !packet.isReceiveFinished()) {
|
||||||
unfinishPacket = packet;
|
unfinishPacket = packet;
|
||||||
if (readBuf.hasRemaining()) {
|
if (readBuffer.hasRemaining()) {
|
||||||
exBuffers.add(readBuf);
|
exBuffers.add(readBuffer);
|
||||||
readBuf = context.pollBuffer();
|
|
||||||
readBuffer = readBuf;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
packets.add(packet);
|
packets.add(packet);
|
||||||
if (packet == null || !readBuf.hasRemaining()) break;
|
if (packet == null || !readBuffer.hasRemaining()) break;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
context.getLogger().log(Level.SEVERE, "WebSocket parse message error", e);
|
context.getLogger().log(Level.SEVERE, "WebSocket parse message error", e);
|
||||||
webSocket.onOccurException(e, null);
|
webSocket.onOccurException(e, null);
|
||||||
}
|
}
|
||||||
//继续监听消息
|
//继续监听消息
|
||||||
readBuf.clear();
|
if (readBuffer.hasRemaining()) { //exBuffers缓存了
|
||||||
|
readBuffer = context.pollBuffer();
|
||||||
|
} else {
|
||||||
|
readBuffer.clear();
|
||||||
|
}
|
||||||
if (halfBytes.getValue() != null) {
|
if (halfBytes.getValue() != null) {
|
||||||
readBuf.put(halfBytes.getValue());
|
readBuffer.put(halfBytes.getValue());
|
||||||
halfBytes.setValue(null);
|
halfBytes.setValue(null);
|
||||||
}
|
}
|
||||||
channel.read(readBuf, null, this);
|
channel.setReadBuffer(readBuffer);
|
||||||
|
channel.read(this);
|
||||||
|
|
||||||
//消息处理
|
//消息处理
|
||||||
for (final WebSocketPacket packet : packets) {
|
for (final WebSocketPacket packet : packets) {
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner abort on decode WebSocketPacket, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner abort on decode WebSocketPacket, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
||||||
failed(null, attachment1);
|
failed(null, readBuffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (packet.receiveMessage == WebSocketPacket.MESSAGE_NIL) continue; //last=false && mergemsg=true 的粘包
|
||||||
|
|
||||||
if (packet.type == FrameType.TEXT) {
|
if (packet.type == FrameType.TEXT) {
|
||||||
try {
|
try {
|
||||||
@@ -175,7 +181,7 @@ class WebSocketRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
} else if (packet.type == FrameType.PONG) {
|
} else if (packet.type == FrameType.PONG) {
|
||||||
try {
|
try {
|
||||||
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner onMessage by PONG FrameType : " + packet);
|
//if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner onMessage by PONG FrameType : " + packet);
|
||||||
webSocket.onPong((byte[]) packet.receiveMessage);
|
webSocket.onPong((byte[]) packet.receiveMessage);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
context.getLogger().log(Level.SEVERE, "WebSocket onPong error (" + packet + ")", e);
|
context.getLogger().log(Level.SEVERE, "WebSocket onPong error (" + packet + ")", e);
|
||||||
@@ -197,7 +203,7 @@ class WebSocketRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer attachment2) {
|
||||||
if (exc != null) {
|
if (exc != null) {
|
||||||
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner read WebSocketPacket failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
|
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner read WebSocketPacket failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
|
||||||
closeRunner(CLOSECODE_WSEXCEPTION, "read websocket-packet failed");
|
closeRunner(CLOSECODE_WSEXCEPTION, "read websocket-packet failed");
|
||||||
@@ -277,8 +283,8 @@ class WebSocketRunner implements Runnable {
|
|||||||
public void failed(Throwable exc, ByteBuffer[] attachments) {
|
public void failed(Throwable exc, ByteBuffer[] attachments) {
|
||||||
future.complete(RETCODE_SENDEXCEPTION);
|
future.complete(RETCODE_SENDEXCEPTION);
|
||||||
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on CompletionHandler");
|
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on CompletionHandler");
|
||||||
if (exc != null) {
|
if (exc != null && context.getLogger().isLoggable(Level.FINER)) {
|
||||||
context.getLogger().log(Level.FINE, "WebSocket sendMessage on CompletionHandler failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
|
context.getLogger().log(Level.FINER, "WebSocket sendMessage on CompletionHandler failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -286,7 +292,9 @@ class WebSocketRunner implements Runnable {
|
|||||||
} catch (Exception t) {
|
} catch (Exception t) {
|
||||||
futureResult.complete(RETCODE_SENDEXCEPTION);
|
futureResult.complete(RETCODE_SENDEXCEPTION);
|
||||||
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on channel.write");
|
closeRunner(RETCODE_SENDEXCEPTION, "websocket send message failed on channel.write");
|
||||||
context.getLogger().log(Level.FINE, "WebSocket sendMessage abort, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", t);
|
if (t != null && context.getLogger().isLoggable(Level.FINER)) {
|
||||||
|
context.getLogger().log(Level.FINER, "WebSocket sendMessage abort, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", t);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return futureResult;
|
return futureResult;
|
||||||
@@ -301,26 +309,11 @@ class WebSocketRunner implements Runnable {
|
|||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (closed) return null;
|
if (closed) return null;
|
||||||
closed = true;
|
closed = true;
|
||||||
|
CompletableFuture<Void> future = engine.removeLocalThenClose(webSocket);
|
||||||
channel.dispose();
|
channel.dispose();
|
||||||
context.offerBuffer(readBuffer);
|
|
||||||
readBuffer = null;
|
|
||||||
CompletableFuture<Void> future = engine.removeThenClose(webSocket);
|
|
||||||
webSocket.onClose(code, reason);
|
webSocket.onClose(code, reason);
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class QueueEntry {
|
|
||||||
|
|
||||||
public final CompletableFuture<Integer> future;
|
|
||||||
|
|
||||||
public final WebSocketPacket packet;
|
|
||||||
|
|
||||||
public QueueEntry(CompletableFuture<Integer> future, WebSocketPacket packet) {
|
|
||||||
this.future = future;
|
|
||||||
this.packet = packet;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
@Comment("最大消息体长度, 小于1表示无限制")
|
@Comment("最大消息体长度, 小于1表示无限制")
|
||||||
public static final String WEBPARAM__WSMAXBODY = "wsmaxbody";
|
public static final String WEBPARAM__WSMAXBODY = "wsmaxbody";
|
||||||
|
|
||||||
|
@Comment("接收客户端的分包(last=false)消息时是否自动合并包")
|
||||||
|
public static final String WEBPARAM__WSMERGEMSG = "wsmergemsg";
|
||||||
|
|
||||||
@Comment("加密解密器")
|
@Comment("加密解密器")
|
||||||
public static final String WEBPARAM__CRYPTOR = "cryptor";
|
public static final String WEBPARAM__CRYPTOR = "cryptor";
|
||||||
|
|
||||||
@@ -88,6 +91,9 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
//同RestWebSocket.anyuser
|
//同RestWebSocket.anyuser
|
||||||
protected boolean anyuser = false;
|
protected boolean anyuser = false;
|
||||||
|
|
||||||
|
//同RestWebSocket.mergemsg
|
||||||
|
protected boolean mergemsg = true;
|
||||||
|
|
||||||
//同RestWebSocket.cryptor, 变量名不可改, 被Rest.createRestWebSocketServlet用到
|
//同RestWebSocket.cryptor, 变量名不可改, 被Rest.createRestWebSocketServlet用到
|
||||||
protected Cryptor cryptor;
|
protected Cryptor cryptor;
|
||||||
|
|
||||||
@@ -106,6 +112,9 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
@Resource(name = "$")
|
@Resource(name = "$")
|
||||||
protected WebSocketNode node;
|
protected WebSocketNode node;
|
||||||
|
|
||||||
|
@Resource(name = "SERVER_RESFACTORY")
|
||||||
|
protected ResourceFactory resourceFactory;
|
||||||
|
|
||||||
protected WebSocketServlet() {
|
protected WebSocketServlet() {
|
||||||
Type msgtype = String.class;
|
Type msgtype = String.class;
|
||||||
try {
|
try {
|
||||||
@@ -145,6 +154,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
if (cryptorClass != null && !cryptorClass.isEmpty()) {
|
if (cryptorClass != null && !cryptorClass.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
this.cryptor = (Cryptor) Thread.currentThread().getContextClassLoader().loadClass(cryptorClass).getDeclaredConstructor().newInstance();
|
this.cryptor = (Cryptor) Thread.currentThread().getContextClassLoader().loadClass(cryptorClass).getDeclaredConstructor().newInstance();
|
||||||
|
if (resourceFactory != null && this.cryptor != null) resourceFactory.inject(this.cryptor);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -153,7 +163,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
}
|
}
|
||||||
//存在WebSocketServlet,则此WebSocketNode必须是本地模式Service
|
//存在WebSocketServlet,则此WebSocketNode必须是本地模式Service
|
||||||
this.node.localEngine = new WebSocketEngine("WebSocketEngine-" + addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]",
|
this.node.localEngine = new WebSocketEngine("WebSocketEngine-" + addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]",
|
||||||
this.single, context, liveinterval, wsmaxconns, wsthreads, wsmaxbody, this.cryptor, this.node, this.sendConvert, logger);
|
this.single, context, liveinterval, wsmaxconns, wsthreads, wsmaxbody, mergemsg, this.cryptor, this.node, this.sendConvert, logger);
|
||||||
this.node.init(conf);
|
this.node.init(conf);
|
||||||
this.node.localEngine.init(conf);
|
this.node.localEngine.init(conf);
|
||||||
|
|
||||||
@@ -251,7 +261,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
CompletableFuture<Boolean> rcFuture = webSocket.onSingleRepeatConnect();
|
CompletableFuture<Boolean> rcFuture = webSocket.onSingleRepeatConnect();
|
||||||
Consumer<Boolean> task = (oldkilled) -> {
|
Consumer<Boolean> task = (oldkilled) -> {
|
||||||
if (oldkilled) {
|
if (oldkilled) {
|
||||||
WebSocketServlet.this.node.localEngine.add(webSocket);
|
WebSocketServlet.this.node.localEngine.addLocal(webSocket);
|
||||||
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
|
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
|
||||||
webSocket._runner = runner;
|
webSocket._runner = runner;
|
||||||
context.runAsync(runner);
|
context.runAsync(runner);
|
||||||
@@ -272,7 +282,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
WebSocketServlet.this.node.localEngine.add(webSocket);
|
WebSocketServlet.this.node.localEngine.addLocal(webSocket);
|
||||||
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
|
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
|
||||||
webSocket._runner = runner;
|
webSocket._runner = runner;
|
||||||
context.runAsync(runner);
|
context.runAsync(runner);
|
||||||
@@ -280,7 +290,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
WebSocketServlet.this.node.localEngine.add(webSocket);
|
WebSocketServlet.this.node.localEngine.addLocal(webSocket);
|
||||||
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
|
WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer, response.removeChannel());
|
||||||
webSocket._runner = runner;
|
webSocket._runner = runner;
|
||||||
context.runAsync(runner);
|
context.runAsync(runner);
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ public final class SncpClient {
|
|||||||
byte i;
|
byte i;
|
||||||
while ((i = reader.readByte()) != 0) {
|
while ((i = reader.readByte()) != 0) {
|
||||||
final Attribute attr = action.paramAttrs[i];
|
final Attribute attr = action.paramAttrs[i];
|
||||||
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
|
attr.set(params[i - 1], bsonConvert.convertFrom(attr.genericType(), reader));
|
||||||
}
|
}
|
||||||
Object rs = bsonConvert.convertFrom(Object.class, reader);
|
Object rs = bsonConvert.convertFrom(Object.class, reader);
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ public final class SncpClient {
|
|||||||
byte i;
|
byte i;
|
||||||
while ((i = reader.readByte()) != 0) {
|
while ((i = reader.readByte()) != 0) {
|
||||||
final Attribute attr = action.paramAttrs[i];
|
final Attribute attr = action.paramAttrs[i];
|
||||||
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
|
attr.set(params[i - 1], bsonConvert.convertFrom(attr.genericType(), reader));
|
||||||
}
|
}
|
||||||
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
||||||
} catch (RpcRemoteException re) {
|
} catch (RpcRemoteException re) {
|
||||||
@@ -370,7 +370,6 @@ public final class SncpClient {
|
|||||||
final ByteBuffer[] sendBuffers = writer.toBuffers();
|
final ByteBuffer[] sendBuffers = writer.toBuffers();
|
||||||
fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength);
|
fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength);
|
||||||
|
|
||||||
final ByteBuffer buffer = transport.pollBuffer();
|
|
||||||
conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() {
|
conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -394,24 +393,24 @@ public final class SncpClient {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//----------------------- 读取返回结果 -------------------------------------
|
//----------------------- 读取返回结果 -------------------------------------
|
||||||
buffer.clear();
|
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
conn.read(buffer, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
|
|
||||||
private byte[] body;
|
private byte[] body;
|
||||||
|
|
||||||
private int received;
|
private int received;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer count, Void attachment2) {
|
public void completed(Integer count, ByteBuffer buffer) {
|
||||||
try {
|
try {
|
||||||
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
|
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
|
||||||
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
|
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
|
||||||
transport.offerBuffer(buffer);
|
conn.offerBuffer(buffer);
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (received < 1 && buffer.limit() < buffer.remaining() + HEADER_SIZE) { //header都没读全
|
if (received < 1 && buffer.limit() < buffer.remaining() + HEADER_SIZE) { //header都没读全
|
||||||
conn.read(buffer, attachment2, this);
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
@@ -421,8 +420,10 @@ public final class SncpClient {
|
|||||||
buffer.get(body, offset, Math.min(buffer.remaining(), this.body.length - offset));
|
buffer.get(body, offset, Math.min(buffer.remaining(), this.body.length - offset));
|
||||||
if (this.received < this.body.length) {// 数据仍然不全,需要继续读取
|
if (this.received < this.body.length) {// 数据仍然不全,需要继续读取
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, attachment2, this);
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(this);
|
||||||
} else {
|
} else {
|
||||||
|
conn.offerBuffer(buffer);
|
||||||
success();
|
success();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -441,10 +442,12 @@ public final class SncpClient {
|
|||||||
this.received = buffer.remaining();
|
this.received = buffer.remaining();
|
||||||
buffer.get(body, 0, this.received);
|
buffer.get(body, 0, this.received);
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, attachment2, this);
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(this);
|
||||||
} else {
|
} else {
|
||||||
this.body = new byte[respBodyLength];
|
this.body = new byte[respBodyLength];
|
||||||
buffer.get(body, 0, respBodyLength);
|
buffer.get(body, 0, respBodyLength);
|
||||||
|
conn.offerBuffer(buffer);
|
||||||
success();
|
success();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@@ -461,7 +464,6 @@ public final class SncpClient {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void success() {
|
public void success() {
|
||||||
future.complete(this.body);
|
future.complete(this.body);
|
||||||
transport.offerBuffer(buffer);
|
|
||||||
transport.offerConnection(false, conn);
|
transport.offerConnection(false, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
@@ -471,7 +473,7 @@ public final class SncpClient {
|
|||||||
int i;
|
int i;
|
||||||
while ((i = (reader.readByte() & 0xff)) != 0) {
|
while ((i = (reader.readByte() & 0xff)) != 0) {
|
||||||
final Attribute attr = action.paramAttrs[i];
|
final Attribute attr = action.paramAttrs[i];
|
||||||
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
|
attr.set(params[i - 1], bsonConvert.convertFrom(attr.genericType(), reader));
|
||||||
}
|
}
|
||||||
Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
||||||
handler.completed(rs, handlerAttach);
|
handler.completed(rs, handlerAttach);
|
||||||
@@ -484,9 +486,9 @@ public final class SncpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer attachment2) {
|
||||||
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
||||||
transport.offerBuffer(buffer);
|
conn.offerBuffer(attachment2);
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
@@ -500,7 +502,6 @@ public final class SncpClient {
|
|||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer[] attachment) {
|
public void failed(Throwable exc, ByteBuffer[] attachment) {
|
||||||
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
||||||
transport.offerBuffer(buffer);
|
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.net.sncp;
|
package org.redkale.net.sncp;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.function.*;
|
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,21 +19,6 @@ public class SncpContext extends Context {
|
|||||||
super(config);
|
super(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Consumer<ByteBuffer> getBufferConsumer() {
|
|
||||||
return super.getBufferConsumer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void offerBuffer(ByteBuffer buffer) {
|
|
||||||
super.offerBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void offerBuffer(ByteBuffer... buffers) {
|
|
||||||
super.offerBuffer(buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SncpContextConfig extends ContextConfig {
|
public static class SncpContextConfig extends ContextConfig {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.nio.*;
|
|||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import javax.annotation.*;
|
import javax.annotation.*;
|
||||||
@@ -36,9 +37,9 @@ import org.redkale.service.RpcCall;
|
|||||||
*/
|
*/
|
||||||
public final class SncpDynServlet extends SncpServlet {
|
public final class SncpDynServlet extends SncpServlet {
|
||||||
|
|
||||||
private static volatile int maxClassNameLength = 0;
|
private final AtomicInteger maxClassNameLength;
|
||||||
|
|
||||||
private static volatile int maxNameLength = 0;
|
private final AtomicInteger maxNameLength;
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(SncpDynServlet.class.getSimpleName());
|
private static final Logger logger = Logger.getLogger(SncpDynServlet.class.getSimpleName());
|
||||||
|
|
||||||
@@ -48,8 +49,11 @@ public final class SncpDynServlet extends SncpServlet {
|
|||||||
|
|
||||||
private Supplier<ByteBuffer> bufferSupplier;
|
private Supplier<ByteBuffer> bufferSupplier;
|
||||||
|
|
||||||
public SncpDynServlet(final BsonConvert convert, final String serviceName, final Class serviceOrSourceType, final Service service) {
|
public SncpDynServlet(final BsonConvert convert, final String serviceName, final Class serviceOrSourceType, final Service service,
|
||||||
|
final AtomicInteger maxClassNameLength, AtomicInteger maxNameLength) {
|
||||||
super(serviceName, serviceOrSourceType, service);
|
super(serviceName, serviceOrSourceType, service);
|
||||||
|
this.maxClassNameLength = maxClassNameLength;
|
||||||
|
this.maxNameLength = maxNameLength;
|
||||||
this.serviceid = Sncp.hash(type.getName() + ':' + serviceName);
|
this.serviceid = Sncp.hash(type.getName() + ':' + serviceName);
|
||||||
Set<DLong> actionids = new HashSet<>();
|
Set<DLong> actionids = new HashSet<>();
|
||||||
for (java.lang.reflect.Method method : service.getClass().getMethods()) {
|
for (java.lang.reflect.Method method : service.getClass().getMethods()) {
|
||||||
@@ -70,20 +74,20 @@ public final class SncpDynServlet extends SncpServlet {
|
|||||||
actions.put(actionid, action);
|
actions.put(actionid, action);
|
||||||
actionids.add(actionid);
|
actionids.add(actionid);
|
||||||
}
|
}
|
||||||
maxNameLength = Math.max(maxNameLength, serviceName.length() + 1);
|
maxNameLength.set(Math.max(maxNameLength.get(), serviceName.length() + 1));
|
||||||
maxClassNameLength = Math.max(maxClassNameLength, type.getName().length());
|
maxClassNameLength.set(Math.max(maxClassNameLength.get(), type.getName().length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(this.getClass().getSimpleName()).append(" (type=").append(type.getName());
|
sb.append(this.getClass().getSimpleName()).append(" (type=").append(type.getName());
|
||||||
int len = maxClassNameLength - type.getName().length();
|
int len = this.maxClassNameLength.get() - type.getName().length();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
}
|
}
|
||||||
sb.append(", serviceid=").append(serviceid).append(", name='").append(serviceName).append("'");
|
sb.append(", serviceid=").append(serviceid).append(", name='").append(serviceName).append("'");
|
||||||
for (int i = 0; i < maxNameLength - serviceName.length(); i++) {
|
for (int i = 0; i < this.maxNameLength.get() - serviceName.length(); i++) {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
}
|
}
|
||||||
sb.append(", actions.size=").append(actions.size() > 9 ? "" : " ").append(actions.size()).append(")");
|
sb.append(", actions.size=").append(actions.size() > 9 ? "" : " ").append(actions.size()).append(")");
|
||||||
@@ -196,7 +200,7 @@ public final class SncpDynServlet extends SncpServlet {
|
|||||||
org.redkale.util.Attribute attr = paramAttrs[i];
|
org.redkale.util.Attribute attr = paramAttrs[i];
|
||||||
if (attr == null) continue;
|
if (attr == null) continue;
|
||||||
out.writeByte((byte) i);
|
out.writeByte((byte) i);
|
||||||
convert.convertTo(out, attr.type(), attr.get(params[i - 1]));
|
convert.convertTo(out, attr.genericType(), attr.get(params[i - 1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.writeByte((byte) 0);
|
out.writeByte((byte) 0);
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ import org.redkale.util.*;
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class SncpServer extends Server<DLong, SncpContext, SncpRequest, SncpResponse, SncpServlet> {
|
public class SncpServer extends Server<DLong, SncpContext, SncpRequest, SncpResponse, SncpServlet> {
|
||||||
|
|
||||||
|
private final AtomicInteger maxClassNameLength = new AtomicInteger();
|
||||||
|
|
||||||
|
private final AtomicInteger maxNameLength = new AtomicInteger();
|
||||||
|
|
||||||
public SncpServer() {
|
public SncpServer() {
|
||||||
this(System.currentTimeMillis(), ResourceFactory.root());
|
this(System.currentTimeMillis(), ResourceFactory.root());
|
||||||
}
|
}
|
||||||
@@ -87,7 +91,8 @@ public class SncpServer extends Server<DLong, SncpContext, SncpRequest, SncpResp
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addSncpServlet(Service sncpService) {
|
public void addSncpServlet(Service sncpService) {
|
||||||
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), Sncp.getResourceName(sncpService), Sncp.getResourceType(sncpService), sncpService);
|
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), Sncp.getResourceName(sncpService),
|
||||||
|
Sncp.getResourceType(sncpService), sncpService, maxClassNameLength, maxNameLength);
|
||||||
this.prepare.addServlet(sds, null, Sncp.getConf(sncpService));
|
this.prepare.addServlet(sds, null, Sncp.getConf(sncpService));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ public class RetResult<T> {
|
|||||||
return new RetResult();
|
return new RetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> RetResult<T> success(T result) {
|
||||||
|
return new RetResult().result(result);
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> CompletableFuture<RetResult<T>> successFuture() {
|
public static <T> CompletableFuture<RetResult<T>> successFuture() {
|
||||||
return CompletableFuture.completedFuture(new RetResult());
|
return CompletableFuture.completedFuture(new RetResult());
|
||||||
}
|
}
|
||||||
@@ -203,6 +207,18 @@ public class RetResult<T> {
|
|||||||
return attach;
|
return attach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取附件元素值
|
||||||
|
*
|
||||||
|
* @param name 元素名
|
||||||
|
* @param defValue 默认值
|
||||||
|
*
|
||||||
|
* @return 结果值
|
||||||
|
*/
|
||||||
|
public String getAttach(String name, String defValue) {
|
||||||
|
return attach == null ? defValue : attach.getOrDefault(name, defValue);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置结果附件
|
* 设置结果附件
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -56,27 +56,27 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable userid) {
|
public CompletableFuture<Integer> sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids) {
|
||||||
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
return this.localEngine.sendMessage(message, last, userid);
|
return this.localEngine.sendLocalMessage(message, last, userids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketRange wsrange, Object message, boolean last) {
|
public CompletableFuture<Integer> broadcastMessage(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketRange wsrange, Object message, boolean last) {
|
||||||
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
return this.localEngine.broadcastMessage(wsrange, message, last);
|
return this.localEngine.broadcastLocalMessage(wsrange, message, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action, Serializable userid) {
|
public CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action, Serializable... userids) {
|
||||||
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
return this.localEngine.sendAction(action, userid);
|
return this.localEngine.sendLocalAction(action, userids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Integer> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action) {
|
public CompletableFuture<Integer> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action) {
|
||||||
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
return this.localEngine.broadcastAction(action);
|
return this.localEngine.broadcastLocalAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -200,62 +200,61 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static void main(String[] args) throws Exception {
|
||||||
* public static void main(String[] args) throws Exception {
|
AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue();
|
||||||
* AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue();
|
conf.addValue("node", new AnyValue.DefaultAnyValue().addValue("addr", "127.0.0.1").addValue("port", "6379"));
|
||||||
* conf.addValue("node", new AnyValue.DefaultAnyValue().addValue("addr", "127.0.0.1").addValue("port", "6379"));
|
|
||||||
*
|
CacheMemorySource source = new CacheMemorySource();
|
||||||
* CacheMemorySource source = new CacheMemorySource();
|
source.defaultConvert = JsonFactory.root().getConvert();
|
||||||
* source.defaultConvert = JsonFactory.root().getConvert();
|
source.initValueType(String.class); //value用String类型
|
||||||
* source.initValueType(String.class); //value用String类型
|
source.initTransient(false);
|
||||||
* source.initTransient(false);
|
source.init(conf);
|
||||||
* source.init(conf);
|
|
||||||
*
|
System.out.println("------------------------------------");
|
||||||
* System.out.println("------------------------------------");
|
source.remove("key1");
|
||||||
* source.remove("key1");
|
source.remove("key2");
|
||||||
* source.remove("key2");
|
source.remove("300");
|
||||||
* source.remove("300");
|
source.set("key1", "value1");
|
||||||
* source.set("key1", "value1");
|
source.setString("keystr1", "strvalue1");
|
||||||
* source.setString("keystr1", "strvalue1");
|
source.setLong("keylong1", 333L);
|
||||||
* source.setLong("keylong1", 333L);
|
source.set("300", "4000");
|
||||||
* source.set("300", "4000");
|
source.getAndRefresh("key1", 3500);
|
||||||
* source.getAndRefresh("key1", 3500);
|
System.out.println("[有值] 300 GET : " + source.get("300"));
|
||||||
* System.out.println("[有值] 300 GET : " + source.get("300"));
|
System.out.println("[有值] key1 GET : " + source.get("key1"));
|
||||||
* System.out.println("[有值] key1 GET : " + source.get("key1"));
|
System.out.println("[无值] key2 GET : " + source.get("key2"));
|
||||||
* System.out.println("[无值] key2 GET : " + source.get("key2"));
|
System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
|
||||||
* System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
|
System.out.println("[有值] key1 EXISTS : " + source.exists("key1"));
|
||||||
* System.out.println("[有值] key1 EXISTS : " + source.exists("key1"));
|
System.out.println("[无值] key2 EXISTS : " + source.exists("key2"));
|
||||||
* System.out.println("[无值] key2 EXISTS : " + source.exists("key2"));
|
|
||||||
*
|
source.remove("keys3");
|
||||||
* source.remove("keys3");
|
source.appendListItem("keys3", "vals1");
|
||||||
* source.appendListItem("keys3", "vals1");
|
source.appendListItem("keys3", "vals2");
|
||||||
* source.appendListItem("keys3", "vals2");
|
System.out.println("-------- keys3 追加了两个值 --------");
|
||||||
* System.out.println("-------- keys3 追加了两个值 --------");
|
System.out.println("[两值] keys3 VALUES : " + source.getCollection("keys3"));
|
||||||
* System.out.println("[两值] keys3 VALUES : " + source.getCollection("keys3"));
|
System.out.println("[有值] keys3 EXISTS : " + source.exists("keys3"));
|
||||||
* System.out.println("[有值] keys3 EXISTS : " + source.exists("keys3"));
|
source.removeListItem("keys3", "vals1");
|
||||||
* source.removeListItem("keys3", "vals1");
|
System.out.println("[一值] keys3 VALUES : " + source.getCollection("keys3"));
|
||||||
* System.out.println("[一值] keys3 VALUES : " + source.getCollection("keys3"));
|
source.getCollectionAndRefresh("keys3", 3000);
|
||||||
* source.getCollectionAndRefresh("keys3", 3000);
|
|
||||||
*
|
source.remove("sets3");
|
||||||
* source.remove("sets3");
|
source.appendSetItem("sets3", "setvals1");
|
||||||
* source.appendSetItem("sets3", "setvals1");
|
source.appendSetItem("sets3", "setvals2");
|
||||||
* source.appendSetItem("sets3", "setvals2");
|
source.appendSetItem("sets3", "setvals1");
|
||||||
* source.appendSetItem("sets3", "setvals1");
|
System.out.println("[两值] sets3 VALUES : " + source.getCollection("sets3"));
|
||||||
* System.out.println("[两值] sets3 VALUES : " + source.getCollection("sets3"));
|
System.out.println("[有值] sets3 EXISTS : " + source.exists("sets3"));
|
||||||
* System.out.println("[有值] sets3 EXISTS : " + source.exists("sets3"));
|
source.removeSetItem("sets3", "setvals1");
|
||||||
* source.removeSetItem("sets3", "setvals1");
|
System.out.println("[一值] sets3 VALUES : " + source.getCollection("sets3"));
|
||||||
* System.out.println("[一值] sets3 VALUES : " + source.getCollection("sets3"));
|
System.out.println("sets3 大小 : " + source.getCollectionSize("sets3"));
|
||||||
* System.out.println("sets3 大小 : " + source.getCollectionSize("sets3"));
|
System.out.println("all keys: " + source.queryKeys());
|
||||||
* System.out.println("all keys: " + source.queryKeys());
|
System.out.println("newnum 值 : " + source.incr("newnum"));
|
||||||
* System.out.println("newnum 值 : " + source.incr("newnum"));
|
System.out.println("newnum 值 : " + source.decr("newnum"));
|
||||||
* System.out.println("newnum 值 : " + source.decr("newnum"));
|
System.out.println("------------------------------------");
|
||||||
* System.out.println("------------------------------------");
|
source.destroy(null);
|
||||||
* source.destroy(null);
|
source.init(null);
|
||||||
* source.init(null);
|
System.out.println("all keys: " + source.queryKeys());
|
||||||
* System.out.println("all keys: " + source.queryKeys());
|
System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
|
||||||
* System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L));
|
}
|
||||||
* }
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception { //给Application 关闭时调用
|
public void close() throws Exception { //给Application 关闭时调用
|
||||||
destroy(null);
|
destroy(null);
|
||||||
@@ -677,16 +676,46 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
|
|||||||
return (Collection<T>) get(key);
|
return (Collection<T>) get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Map<String, Collection<T>> getCollectionMap(final Type componentType, final String... keys) {
|
||||||
|
Map<String, Collection<T>> map = new HashMap<>();
|
||||||
|
for (String key : keys) {
|
||||||
|
Collection<T> s = (Collection<T>) get(key);
|
||||||
|
if (s != null) map.put(key, s);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> getStringCollection(final String key) {
|
public Collection<String> getStringCollection(final String key) {
|
||||||
return (Collection<String>) get(key);
|
return (Collection<String>) get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Collection<String>> getStringCollectionMap(final String... keys) {
|
||||||
|
Map<String, Collection<String>> map = new HashMap<>();
|
||||||
|
for (String key : keys) {
|
||||||
|
Collection<String> s = (Collection<String>) get(key);
|
||||||
|
if (s != null) map.put(key, s);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Long> getLongCollection(final String key) {
|
public Collection<Long> getLongCollection(final String key) {
|
||||||
return (Collection<Long>) get(key);
|
return (Collection<Long>) get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Collection<Long>> getLongCollectionMap(final String... keys) {
|
||||||
|
Map<String, Collection<Long>> map = new HashMap<>();
|
||||||
|
for (String key : keys) {
|
||||||
|
Collection<Long> s = (Collection<Long>) get(key);
|
||||||
|
if (s != null) map.put(key, s);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Collection<V>> getCollectionAsync(final String key) {
|
public CompletableFuture<Collection<V>> getCollectionAsync(final String key) {
|
||||||
return CompletableFuture.supplyAsync(() -> getCollection(key), getExecutor());
|
return CompletableFuture.supplyAsync(() -> getCollection(key), getExecutor());
|
||||||
@@ -697,16 +726,31 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
|
|||||||
return CompletableFuture.supplyAsync(() -> getCollection(key, componentType), getExecutor());
|
return CompletableFuture.supplyAsync(() -> getCollection(key, componentType), getExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Map<String, Collection<V>>> getCollectionMapAsync(final Type componentType, final String... keys) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> getCollectionMap(componentType, keys), getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Collection<String>> getStringCollectionAsync(final String key) {
|
public CompletableFuture<Collection<String>> getStringCollectionAsync(final String key) {
|
||||||
return CompletableFuture.supplyAsync(() -> getStringCollection(key), getExecutor());
|
return CompletableFuture.supplyAsync(() -> getStringCollection(key), getExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Map<String, Collection<String>>> getStringCollectionMapAsync(final String... keys) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> getStringCollectionMap(keys), getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Collection<Long>> getLongCollectionAsync(final String key) {
|
public CompletableFuture<Collection<Long>> getLongCollectionAsync(final String key) {
|
||||||
return CompletableFuture.supplyAsync(() -> getLongCollection(key), getExecutor());
|
return CompletableFuture.supplyAsync(() -> getLongCollection(key), getExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Map<String, Collection<Long>>> getLongCollectionMapAsync(final String... keys) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> getLongCollectionMap(keys), getExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCollectionSize(final String key) {
|
public int getCollectionSize(final String key) {
|
||||||
Collection<V> collection = (Collection<V>) get(key);
|
Collection<V> collection = (Collection<V>) get(key);
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ public interface CacheSource<V extends Object> {
|
|||||||
|
|
||||||
public <T> Collection<T> getCollection(final String key, final Type componentType);
|
public <T> Collection<T> getCollection(final String key, final Type componentType);
|
||||||
|
|
||||||
|
public <T> Map<String, Collection<T>> getCollectionMap(final Type componentType, final String... keys);
|
||||||
|
|
||||||
public int getCollectionSize(final String key);
|
public int getCollectionSize(final String key);
|
||||||
|
|
||||||
public Collection<V> getCollectionAndRefresh(final String key, final int expireSeconds);
|
public Collection<V> getCollectionAndRefresh(final String key, final int expireSeconds);
|
||||||
@@ -138,6 +140,8 @@ public interface CacheSource<V extends Object> {
|
|||||||
|
|
||||||
public Collection<String> getStringCollection(final String key);
|
public Collection<String> getStringCollection(final String key);
|
||||||
|
|
||||||
|
public Map<String, Collection<String>> getStringCollectionMap(final String... keys);
|
||||||
|
|
||||||
public Collection<String> getStringCollectionAndRefresh(final String key, final int expireSeconds);
|
public Collection<String> getStringCollectionAndRefresh(final String key, final int expireSeconds);
|
||||||
|
|
||||||
public void appendStringListItem(final String key, final String value);
|
public void appendStringListItem(final String key, final String value);
|
||||||
@@ -160,6 +164,8 @@ public interface CacheSource<V extends Object> {
|
|||||||
|
|
||||||
public Collection<Long> getLongCollection(final String key);
|
public Collection<Long> getLongCollection(final String key);
|
||||||
|
|
||||||
|
public Map<String, Collection<Long>> getLongCollectionMap(final String... keys);
|
||||||
|
|
||||||
public Collection<Long> getLongCollectionAndRefresh(final String key, final int expireSeconds);
|
public Collection<Long> getLongCollectionAndRefresh(final String key, final int expireSeconds);
|
||||||
|
|
||||||
public void appendLongListItem(final String key, final long value);
|
public void appendLongListItem(final String key, final long value);
|
||||||
@@ -235,6 +241,8 @@ public interface CacheSource<V extends Object> {
|
|||||||
|
|
||||||
public <T> CompletableFuture<Collection<T>> getCollectionAsync(final String key, final Type componentType);
|
public <T> CompletableFuture<Collection<T>> getCollectionAsync(final String key, final Type componentType);
|
||||||
|
|
||||||
|
public <T> CompletableFuture<Map<String, Collection<T>>> getCollectionMapAsync(final Type componentType, final String... keys);
|
||||||
|
|
||||||
public CompletableFuture<Integer> getCollectionSizeAsync(final String key);
|
public CompletableFuture<Integer> getCollectionSizeAsync(final String key);
|
||||||
|
|
||||||
public CompletableFuture<Collection<V>> getCollectionAndRefreshAsync(final String key, final int expireSeconds);
|
public CompletableFuture<Collection<V>> getCollectionAndRefreshAsync(final String key, final int expireSeconds);
|
||||||
@@ -281,6 +289,8 @@ public interface CacheSource<V extends Object> {
|
|||||||
|
|
||||||
public CompletableFuture<Collection<String>> getStringCollectionAsync(final String key);
|
public CompletableFuture<Collection<String>> getStringCollectionAsync(final String key);
|
||||||
|
|
||||||
|
public CompletableFuture<Map<String, Collection<String>>> getStringCollectionMapAsync(final String... keys);
|
||||||
|
|
||||||
public CompletableFuture<Collection<String>> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds);
|
public CompletableFuture<Collection<String>> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds);
|
||||||
|
|
||||||
public CompletableFuture<Void> appendStringListItemAsync(final String key, final String value);
|
public CompletableFuture<Void> appendStringListItemAsync(final String key, final String value);
|
||||||
@@ -303,6 +313,8 @@ public interface CacheSource<V extends Object> {
|
|||||||
|
|
||||||
public CompletableFuture<Collection<Long>> getLongCollectionAsync(final String key);
|
public CompletableFuture<Collection<Long>> getLongCollectionAsync(final String key);
|
||||||
|
|
||||||
|
public CompletableFuture<Map<String, Collection<Long>>> getLongCollectionMapAsync(final String... keys);
|
||||||
|
|
||||||
public CompletableFuture<Collection<Long>> getLongCollectionAndRefreshAsync(final String key, final int expireSeconds);
|
public CompletableFuture<Collection<Long>> getLongCollectionAndRefreshAsync(final String key, final int expireSeconds);
|
||||||
|
|
||||||
public CompletableFuture<Void> appendLongListItemAsync(final String key, final long value);
|
public CompletableFuture<Void> appendLongListItemAsync(final String key, final long value);
|
||||||
|
|||||||
30
src/org/redkale/source/CryptColumn.java
Normal file
30
src/org/redkale/source/CryptColumn.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.source;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.FIELD;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密字段标记 <br>
|
||||||
|
* 注意: 加密字段不能用于 LIKE 等过滤查询 <br>
|
||||||
|
* 如果有对加密字段进行过滤查询的需求,就要保证加密算法也能兼容LIKE,如:"abc"的加密字符串也是"abcde"的加密字符串的一部分
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target({FIELD})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface CryptColumn {
|
||||||
|
|
||||||
|
Class<? extends CryptHandler> handler();
|
||||||
|
}
|
||||||
38
src/org/redkale/source/CryptHandler.java
Normal file
38
src/org/redkale/source/CryptHandler.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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.source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段加密解密接口
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @since 2.0.0
|
||||||
|
* @param <S> 加密的字段类型
|
||||||
|
* @param <D> 加密后的数据类型
|
||||||
|
*/
|
||||||
|
public interface CryptHandler<S, D> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*
|
||||||
|
* @param value 加密前的字段值
|
||||||
|
*
|
||||||
|
* @return 加密后的字段值
|
||||||
|
*/
|
||||||
|
public D encrypt(S value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
*
|
||||||
|
* @param value 加密的字段值
|
||||||
|
*
|
||||||
|
* @return 解密后的字段值
|
||||||
|
*/
|
||||||
|
public S decrypt(D value);
|
||||||
|
}
|
||||||
@@ -20,5 +20,5 @@ public interface DataCacheListener {
|
|||||||
|
|
||||||
public <T> int updateCache(Class<T> clazz, T... entitys);
|
public <T> int updateCache(Class<T> clazz, T... entitys);
|
||||||
|
|
||||||
public <T> int deleteCache(Class<T> clazz, Serializable... ids);
|
public <T> int deleteCache(Class<T> clazz, Serializable... pks);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,18 +50,18 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... values) {
|
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... entitys) {
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
int c = 0;
|
int c = 0;
|
||||||
conn = writePool.poll();
|
conn = writePool.poll();
|
||||||
final String sql = info.getInsertPrepareSQL(values[0]);
|
final String sql = info.getInsertPrepareSQL(entitys[0]);
|
||||||
final Class primaryType = info.getPrimary().type();
|
final Class primaryType = info.getPrimary().type();
|
||||||
final Attribute primary = info.getPrimary();
|
final Attribute primary = info.getPrimary();
|
||||||
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
||||||
conn.setReadOnly(false);
|
conn.setReadOnly(false);
|
||||||
conn.setAutoCommit(true);
|
conn.setAutoCommit(true);
|
||||||
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, values);
|
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, entitys);
|
||||||
try {
|
try {
|
||||||
int[] cs = prestmt.executeBatch();
|
int[] cs = prestmt.executeBatch();
|
||||||
int c1 = 0;
|
int c1 = 0;
|
||||||
@@ -73,7 +73,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
if (info.tableStrategy == null || !info.isTableNotExist(se)) throw se;
|
if (info.tableStrategy == null || !info.isTableNotExist(se)) throw se;
|
||||||
synchronized (info.tables) {
|
synchronized (info.tables) {
|
||||||
final String oldTable = info.table;
|
final String oldTable = info.table;
|
||||||
final String newTable = info.getTable(values[0]);
|
final String newTable = info.getTable(entitys[0]);
|
||||||
if (!info.tables.contains(newTable)) {
|
if (!info.tables.contains(newTable)) {
|
||||||
try {
|
try {
|
||||||
Statement st = conn.createStatement();
|
Statement st = conn.createStatement();
|
||||||
@@ -105,7 +105,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
prestmt.close();
|
prestmt.close();
|
||||||
prestmt = createInsertPreparedStatement(conn, sql, info, values);
|
prestmt = createInsertPreparedStatement(conn, sql, info, entitys);
|
||||||
int[] cs = prestmt.executeBatch();
|
int[] cs = prestmt.executeBatch();
|
||||||
int c1 = 0;
|
int c1 = 0;
|
||||||
for (int cc : cs) {
|
for (int cc : cs) {
|
||||||
@@ -118,11 +118,11 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
int i = -1;
|
int i = -1;
|
||||||
while (set.next()) {
|
while (set.next()) {
|
||||||
if (primaryType == int.class) {
|
if (primaryType == int.class) {
|
||||||
primary.set(values[++i], set.getInt(1));
|
primary.set(entitys[++i], set.getInt(1));
|
||||||
} else if (primaryType == long.class) {
|
} else if (primaryType == long.class) {
|
||||||
primary.set(values[++i], set.getLong(1));
|
primary.set(entitys[++i], set.getLong(1));
|
||||||
} else {
|
} else {
|
||||||
primary.set(values[++i], set.getObject(1));
|
primary.set(entitys[++i], set.getObject(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set.close();
|
set.close();
|
||||||
@@ -131,13 +131,13 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息
|
if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息
|
||||||
char[] sqlchars = sql.toCharArray();
|
char[] sqlchars = sql.toCharArray();
|
||||||
for (final T value : values) {
|
for (final T value : entitys) {
|
||||||
//-----------------------------
|
//-----------------------------
|
||||||
StringBuilder sb = new StringBuilder(128);
|
StringBuilder sb = new StringBuilder(128);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (char ch : sqlchars) {
|
for (char ch : sqlchars) {
|
||||||
if (ch == '?') {
|
if (ch == '?') {
|
||||||
Object obj = attrs[i++].get(value);
|
Object obj = info.getSQLValue(attrs[i++], value);
|
||||||
if (obj != null && obj.getClass().isArray()) {
|
if (obj != null && obj.getClass().isArray()) {
|
||||||
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
|
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
|
||||||
} else {
|
} else {
|
||||||
@@ -162,32 +162,40 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected <T> PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
|
protected <T> PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
|
||||||
final EntityInfo<T> info, T... values) throws SQLException {
|
final EntityInfo<T> info, T... entitys) throws SQLException {
|
||||||
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
||||||
final PreparedStatement prestmt = info.autoGenerated ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
|
final PreparedStatement prestmt = info.autoGenerated ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
|
||||||
|
|
||||||
for (final T value : values) {
|
for (final T value : entitys) {
|
||||||
int i = 0;
|
|
||||||
if (info.autouuid) info.createPrimaryValue(value);
|
if (info.autouuid) info.createPrimaryValue(value);
|
||||||
for (Attribute<T, Serializable> attr : attrs) {
|
batchStatementParameters(conn, prestmt, info, attrs, value);
|
||||||
Serializable val = attr.get(value);
|
|
||||||
if (val instanceof byte[]) {
|
|
||||||
Blob blob = conn.createBlob();
|
|
||||||
blob.setBytes(1, (byte[]) val);
|
|
||||||
prestmt.setObject(++i, blob);
|
|
||||||
} else if (val instanceof AtomicInteger) {
|
|
||||||
prestmt.setObject(++i, ((AtomicInteger) val).get());
|
|
||||||
} else if (val instanceof AtomicLong) {
|
|
||||||
prestmt.setObject(++i, ((AtomicLong) val).get());
|
|
||||||
} else {
|
|
||||||
prestmt.setObject(++i, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prestmt.addBatch();
|
prestmt.addBatch();
|
||||||
}
|
}
|
||||||
return prestmt;
|
return prestmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected <T> int batchStatementParameters(Connection conn, PreparedStatement prestmt, EntityInfo<T> info, Attribute<T, Serializable>[] attrs, T entity) throws SQLException {
|
||||||
|
int i = 0;
|
||||||
|
for (Attribute<T, Serializable> attr : attrs) {
|
||||||
|
Serializable val = info.getSQLValue(attr, entity);
|
||||||
|
if (val instanceof byte[]) {
|
||||||
|
Blob blob = conn.createBlob();
|
||||||
|
blob.setBytes(1, (byte[]) val);
|
||||||
|
prestmt.setObject(++i, blob);
|
||||||
|
} else if (val instanceof AtomicInteger) {
|
||||||
|
prestmt.setObject(++i, ((AtomicInteger) val).get());
|
||||||
|
} else if (val instanceof AtomicLong) {
|
||||||
|
prestmt.setObject(++i, ((AtomicLong) val).get());
|
||||||
|
} else if (val != null && !(val instanceof Number) && !(val instanceof CharSequence) && !(entity instanceof java.util.Date)
|
||||||
|
&& !val.getClass().getName().startsWith("java.sql.") && !val.getClass().getName().startsWith("java.time.")) {
|
||||||
|
prestmt.setObject(++i, info.jsonConvert.convertTo(attr.genericType(), val));
|
||||||
|
} else {
|
||||||
|
prestmt.setObject(++i, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> CompletableFuture<Integer> deleteDB(EntityInfo<T> info, Flipper flipper, String sql) {
|
protected <T> CompletableFuture<Integer> deleteDB(EntityInfo<T> info, Flipper flipper, String sql) {
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
@@ -211,34 +219,60 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... values) {
|
protected <T> CompletableFuture<Integer> clearTableDB(EntityInfo<T> info, String sql) {
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = writePool.poll();
|
conn = writePool.poll();
|
||||||
conn.setReadOnly(false);
|
conn.setReadOnly(false);
|
||||||
conn.setAutoCommit(true);
|
conn.setAutoCommit(true);
|
||||||
final String updateSQL = info.getUpdatePrepareSQL(values[0]);
|
final Statement stmt = conn.createStatement();
|
||||||
|
int c = stmt.executeUpdate(sql);
|
||||||
|
stmt.close();
|
||||||
|
return CompletableFuture.completedFuture(c);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
CompletableFuture future = new CompletableFuture();
|
||||||
|
future.completeExceptionally(e);
|
||||||
|
return future;
|
||||||
|
} finally {
|
||||||
|
if (conn != null) writePool.offerConnection(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> CompletableFuture<Integer> dropTableDB(EntityInfo<T> info, String sql) {
|
||||||
|
Connection conn = null;
|
||||||
|
try {
|
||||||
|
conn = writePool.poll();
|
||||||
|
conn.setReadOnly(false);
|
||||||
|
conn.setAutoCommit(true);
|
||||||
|
final Statement stmt = conn.createStatement();
|
||||||
|
int c = stmt.executeUpdate(sql);
|
||||||
|
stmt.close();
|
||||||
|
return CompletableFuture.completedFuture(c);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
CompletableFuture future = new CompletableFuture();
|
||||||
|
future.completeExceptionally(e);
|
||||||
|
return future;
|
||||||
|
} finally {
|
||||||
|
if (conn != null) writePool.offerConnection(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... entitys) {
|
||||||
|
Connection conn = null;
|
||||||
|
try {
|
||||||
|
conn = writePool.poll();
|
||||||
|
conn.setReadOnly(false);
|
||||||
|
conn.setAutoCommit(true);
|
||||||
|
final String updateSQL = info.getUpdatePrepareSQL(entitys[0]);
|
||||||
final PreparedStatement prestmt = conn.prepareStatement(updateSQL);
|
final PreparedStatement prestmt = conn.prepareStatement(updateSQL);
|
||||||
Attribute<T, Serializable>[] attrs = info.updateAttributes;
|
Attribute<T, Serializable>[] attrs = info.updateAttributes;
|
||||||
final boolean debugfinest = info.isLoggable(logger, Level.FINEST);
|
final boolean debugfinest = info.isLoggable(logger, Level.FINEST);
|
||||||
char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null;
|
char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null;
|
||||||
final Attribute<T, Serializable> primary = info.getPrimary();
|
final Attribute<T, Serializable> primary = info.getPrimary();
|
||||||
for (final T value : values) {
|
for (final T value : entitys) {
|
||||||
int k = 0;
|
int k = batchStatementParameters(conn, prestmt, info, attrs, value);
|
||||||
for (Attribute<T, Serializable> attr : attrs) {
|
|
||||||
Serializable val = attr.get(value);
|
|
||||||
if (val instanceof byte[]) {
|
|
||||||
Blob blob = conn.createBlob();
|
|
||||||
blob.setBytes(1, (byte[]) val);
|
|
||||||
prestmt.setObject(++k, blob);
|
|
||||||
} else if (val instanceof AtomicInteger) {
|
|
||||||
prestmt.setObject(++k, ((AtomicInteger) val).get());
|
|
||||||
} else if (val instanceof AtomicLong) {
|
|
||||||
prestmt.setObject(++k, ((AtomicLong) val).get());
|
|
||||||
} else {
|
|
||||||
prestmt.setObject(++k, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prestmt.setObject(++k, primary.get(value));
|
prestmt.setObject(++k, primary.get(value));
|
||||||
prestmt.addBatch();//------------------------------------------------------------
|
prestmt.addBatch();//------------------------------------------------------------
|
||||||
if (debugfinest) { //打印调试信息
|
if (debugfinest) { //打印调试信息
|
||||||
@@ -247,7 +281,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
StringBuilder sb = new StringBuilder(128);
|
StringBuilder sb = new StringBuilder(128);
|
||||||
for (char ch : sqlchars) {
|
for (char ch : sqlchars) {
|
||||||
if (ch == '?') {
|
if (ch == '?') {
|
||||||
Object obj = i == attrs.length ? primary.get(value) : attrs[i++].get(value);
|
Object obj = i == attrs.length ? info.getSQLValue(primary, value) : info.getSQLValue(attrs[i++], value);
|
||||||
if (obj != null && obj.getClass().isArray()) {
|
if (obj != null && obj.getClass().isArray()) {
|
||||||
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
|
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
|
||||||
} else {
|
} else {
|
||||||
@@ -258,7 +292,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
String debugsql = sb.toString();
|
String debugsql = sb.toString();
|
||||||
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " update sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
|
if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " updates sql=" + debugsql.replaceAll("(\r|\n)", "\\n"));
|
||||||
} //打印结束
|
} //打印结束
|
||||||
}
|
}
|
||||||
int[] pc = prestmt.executeBatch();
|
int[] pc = prestmt.executeBatch();
|
||||||
@@ -316,7 +350,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = readPool.poll();
|
conn = readPool.poll();
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final Statement stmt = conn.createStatement();
|
final Statement stmt = conn.createStatement();
|
||||||
ResultSet set = stmt.executeQuery(sql);
|
ResultSet set = stmt.executeQuery(sql);
|
||||||
final Map map = new HashMap<>();
|
final Map map = new HashMap<>();
|
||||||
@@ -348,7 +382,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = readPool.poll();
|
conn = readPool.poll();
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final Statement stmt = conn.createStatement();
|
final Statement stmt = conn.createStatement();
|
||||||
Number rs = defVal;
|
Number rs = defVal;
|
||||||
ResultSet set = stmt.executeQuery(sql);
|
ResultSet set = stmt.executeQuery(sql);
|
||||||
@@ -373,7 +407,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = readPool.poll();
|
conn = readPool.poll();
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final Statement stmt = conn.createStatement();
|
final Statement stmt = conn.createStatement();
|
||||||
Map<K, N> rs = new LinkedHashMap<>();
|
Map<K, N> rs = new LinkedHashMap<>();
|
||||||
ResultSet set = stmt.executeQuery(sql);
|
ResultSet set = stmt.executeQuery(sql);
|
||||||
@@ -399,11 +433,11 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = readPool.poll();
|
conn = readPool.poll();
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
ps.setFetchSize(1);
|
ps.setFetchSize(1);
|
||||||
final ResultSet set = ps.executeQuery();
|
final ResultSet set = ps.executeQuery();
|
||||||
T rs = set.next() ? info.getValue(selects, set) : null;
|
T rs = set.next() ? info.getEntityValue(selects, set) : null;
|
||||||
set.close();
|
set.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
return CompletableFuture.completedFuture(rs);
|
return CompletableFuture.completedFuture(rs);
|
||||||
@@ -422,19 +456,14 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = readPool.poll();
|
conn = readPool.poll();
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final Attribute<T, Serializable> attr = info.getAttribute(column);
|
final Attribute<T, Serializable> attr = info.getAttribute(column);
|
||||||
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
ps.setFetchSize(1);
|
ps.setFetchSize(1);
|
||||||
final ResultSet set = ps.executeQuery();
|
final ResultSet set = ps.executeQuery();
|
||||||
Serializable val = defValue;
|
Serializable val = defValue;
|
||||||
if (set.next()) {
|
if (set.next()) {
|
||||||
if (attr.type() == byte[].class) {
|
val = info.getFieldValue(attr, set, 1);
|
||||||
Blob blob = set.getBlob(1);
|
|
||||||
if (blob != null) val = blob.getBytes(1, (int) blob.length());
|
|
||||||
} else {
|
|
||||||
val = (Serializable) set.getObject(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
set.close();
|
set.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -454,7 +483,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = readPool.poll();
|
conn = readPool.poll();
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
final ResultSet set = ps.executeQuery();
|
final ResultSet set = ps.executeQuery();
|
||||||
boolean rs = set.next() ? (set.getInt(1) > 0) : false;
|
boolean rs = set.next() ? (set.getInt(1) > 0) : false;
|
||||||
@@ -473,11 +502,11 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> CompletableFuture<Sheet<T>> querySheetDB(EntityInfo<T> info, boolean needtotal, SelectColumn selects, Flipper flipper, FilterNode node) {
|
protected <T> CompletableFuture<Sheet<T>> querySheetDB(EntityInfo<T> info, final boolean readcache, boolean needtotal, SelectColumn selects, Flipper flipper, FilterNode node) {
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = readPool.poll();
|
conn = readPool.poll();
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final SelectColumn sels = selects;
|
final SelectColumn sels = selects;
|
||||||
final List<T> list = new ArrayList();
|
final List<T> list = new ArrayList();
|
||||||
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
|
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
|
||||||
@@ -487,20 +516,20 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
if ("mysql".equals(dbtype) || "postgresql".equals(dbtype)) {
|
if ("mysql".equals(dbtype) || "postgresql".equals(dbtype)) {
|
||||||
final String listsql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
|
final String listsql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
|
||||||
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + createSQLOrderby(info, flipper) + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset()));
|
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + createSQLOrderby(info, flipper) + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset()));
|
||||||
if (info.isLoggable(logger, Level.FINEST, listsql)) {
|
if (readcache && info.isLoggable(logger, Level.FINEST, listsql)) {
|
||||||
logger.finest(info.getType().getSimpleName() + " query sql=" + listsql);
|
logger.finest(info.getType().getSimpleName() + " query sql=" + listsql);
|
||||||
}
|
}
|
||||||
PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
ResultSet set = ps.executeQuery();
|
ResultSet set = ps.executeQuery();
|
||||||
while (set.next()) {
|
while (set.next()) {
|
||||||
list.add(infoGetValue(info, sels, set));
|
list.add(getEntityValue(info, sels, set));
|
||||||
}
|
}
|
||||||
set.close();
|
set.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
long total = list.size();
|
long total = list.size();
|
||||||
if (needtotal) {
|
if (needtotal) {
|
||||||
final String countsql = "SELECT COUNT(*) FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
|
final String countsql = "SELECT COUNT(*) FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
|
||||||
if (info.isLoggable(logger, Level.FINEST, countsql)) {
|
if (readcache && info.isLoggable(logger, Level.FINEST, countsql)) {
|
||||||
logger.finest(info.getType().getSimpleName() + " query countsql=" + countsql);
|
logger.finest(info.getType().getSimpleName() + " query countsql=" + countsql);
|
||||||
}
|
}
|
||||||
ps = conn.prepareStatement(countsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
ps = conn.prepareStatement(countsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
@@ -513,10 +542,10 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
}
|
}
|
||||||
final String sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
|
final String sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
|
||||||
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper);
|
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper);
|
||||||
if (info.isLoggable(logger, Level.FINEST, sql)) {
|
if (readcache && info.isLoggable(logger, Level.FINEST, sql)) {
|
||||||
logger.finest(info.getType().getSimpleName() + " query sql=" + sql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset())));
|
logger.finest(info.getType().getSimpleName() + " query sql=" + sql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset())));
|
||||||
}
|
}
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
if (flipper != null && flipper.getLimit() > 0) ps.setFetchSize(flipper.getLimit());
|
if (flipper != null && flipper.getLimit() > 0) ps.setFetchSize(flipper.getLimit());
|
||||||
final ResultSet set = ps.executeQuery();
|
final ResultSet set = ps.executeQuery();
|
||||||
@@ -525,7 +554,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
while (set.next()) {
|
while (set.next()) {
|
||||||
i++;
|
i++;
|
||||||
list.add(info.getValue(sels, set));
|
list.add(info.getEntityValue(sels, set));
|
||||||
if (limit <= i) break;
|
if (limit <= i) break;
|
||||||
}
|
}
|
||||||
long total = list.size();
|
long total = list.size();
|
||||||
@@ -606,7 +635,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
final Connection conn = readPool.poll();
|
final Connection conn = readPool.poll();
|
||||||
try {
|
try {
|
||||||
if (logger.isLoggable(Level.FINEST)) logger.finest("direct query sql=" + sql);
|
if (logger.isLoggable(Level.FINEST)) logger.finest("direct query sql=" + sql);
|
||||||
conn.setReadOnly(true);
|
//conn.setReadOnly(true);
|
||||||
final Statement statement = conn.createStatement();
|
final Statement statement = conn.createStatement();
|
||||||
//final PreparedStatement statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
//final PreparedStatement statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
final ResultSet set = statement.executeQuery(sql);// ps.executeQuery();
|
final ResultSet set = statement.executeQuery(sql);// ps.executeQuery();
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public class DataMemorySource extends DataSqlSource<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... values) {
|
protected <T> CompletableFuture<Integer> insertDB(EntityInfo<T> info, T... entitys) {
|
||||||
return CompletableFuture.completedFuture(0);
|
return CompletableFuture.completedFuture(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,17 @@ public class DataMemorySource extends DataSqlSource<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... values) {
|
protected <T> CompletableFuture<Integer> clearTableDB(EntityInfo<T> info, String sql) {
|
||||||
|
return CompletableFuture.completedFuture(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> CompletableFuture<Integer> dropTableDB(EntityInfo<T> info, String sql) {
|
||||||
|
return CompletableFuture.completedFuture(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> CompletableFuture<Integer> updateDB(EntityInfo<T> info, T... entitys) {
|
||||||
return CompletableFuture.completedFuture(0);
|
return CompletableFuture.completedFuture(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +144,7 @@ public class DataMemorySource extends DataSqlSource<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> CompletableFuture<Sheet<T>> querySheetDB(EntityInfo<T> info, boolean needtotal, SelectColumn selects, Flipper flipper, FilterNode node) {
|
protected <T> CompletableFuture<Sheet<T>> querySheetDB(EntityInfo<T> info, final boolean readcache, boolean needtotal, SelectColumn selects, Flipper flipper, FilterNode node) {
|
||||||
return CompletableFuture.completedFuture(new Sheet<>());
|
return CompletableFuture.completedFuture(new Sheet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,60 +32,105 @@ public interface DataSource {
|
|||||||
public String getType();
|
public String getType();
|
||||||
|
|
||||||
//----------------------insertAsync-----------------------------
|
//----------------------insertAsync-----------------------------
|
||||||
|
//insert 暂时不支持Collection、Stream, 因为存在@RpcCall问题
|
||||||
/**
|
/**
|
||||||
* 新增记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
* 新增记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
*
|
*
|
||||||
* @param <T> 泛型
|
* @param <T> 泛型
|
||||||
* @param values Entity对象
|
* @param entitys Entity对象
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int insert(final T... values);
|
public <T> int insert(final T... entitys);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
* 新增记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
*
|
*
|
||||||
* @param <T> 泛型
|
* @param <T> 泛型
|
||||||
* @param values Entity对象
|
* @param entitys Entity对象
|
||||||
*
|
*
|
||||||
* @return CompletableFuture
|
* @return CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> insertAsync(final T... values);
|
public <T> CompletableFuture<Integer> insertAsync(final T... entitys);
|
||||||
|
|
||||||
//-------------------------deleteAsync--------------------------
|
//-------------------------deleteAsync--------------------------
|
||||||
/**
|
/**
|
||||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
||||||
*
|
*
|
||||||
* @param <T> 泛型
|
* @param <T> 泛型
|
||||||
* @param values Entity对象
|
* @param entitys Entity对象
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int delete(final T... values);
|
public <T> int delete(final T... entitys);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
||||||
*
|
*
|
||||||
* @param <T> 泛型
|
* @param <T> 泛型
|
||||||
* @param values Entity对象
|
* @param entitys Entity对象
|
||||||
*
|
|
||||||
* @return 影响的记录条数CompletableFuture
|
|
||||||
*/
|
|
||||||
public <T> CompletableFuture<Integer> deleteAsync(final T... values);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除指定主键值的记录,多主键值必须在同一张表中 <br>
|
|
||||||
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids} <br>
|
|
||||||
*
|
|
||||||
* @param <T> Entity泛型
|
|
||||||
* @param clazz Entity类
|
|
||||||
* @param ids 主键值
|
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int delete(final Class<T> clazz, final Serializable... ids);
|
default <T> int delete(final Collection<T> entitys) {
|
||||||
|
if (entitys == null || entitys.isEmpty()) return 0;
|
||||||
|
return delete(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
default <T> int delete(final Stream<T> entitys) {
|
||||||
|
if (entitys == null) return 0;
|
||||||
|
return delete(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
public <T> CompletableFuture<Integer> deleteAsync(final T... entitys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
default <T> CompletableFuture<Integer> deleteAsync(final Collection<T> entitys) {
|
||||||
|
if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0);
|
||||||
|
return deleteAsync(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定主键值的记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {values.id} <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
default <T> CompletableFuture<Integer> deleteAsync(final Stream<T> entitys) {
|
||||||
|
if (entitys == null) return CompletableFuture.completedFuture(0);
|
||||||
|
return deleteAsync(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除指定主键值的记录,多主键值必须在同一张表中 <br>
|
* 删除指定主键值的记录,多主键值必须在同一张表中 <br>
|
||||||
@@ -93,11 +138,23 @@ public interface DataSource {
|
|||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param ids 主键值
|
* @param pks 主键值
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
public <T> int delete(final Class<T> clazz, final Serializable... pks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定主键值的记录,多主键值必须在同一张表中 <br>
|
||||||
|
* 等价SQL: DELETE FROM {table} WHERE {primary} IN {ids} <br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
* @param pks 主键值
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Serializable... ids);
|
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Serializable... pks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除符合过滤条件的记录 <br>
|
* 删除符合过滤条件的记录 <br>
|
||||||
@@ -151,6 +208,100 @@ public interface DataSource {
|
|||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Flipper flipper, final FilterNode node);
|
public <T> CompletableFuture<Integer> deleteAsync(final Class<T> clazz, final Flipper flipper, final FilterNode node);
|
||||||
|
|
||||||
|
//------------------------clearAsync---------------------------
|
||||||
|
/**
|
||||||
|
* 清空表 <br>
|
||||||
|
* 等价SQL: TRUNCATE TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
public <T> int clearTable(final Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空表 <br>
|
||||||
|
* 等价SQL: TRUNCATE TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
public <T> CompletableFuture<Integer> clearTableAsync(final Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空表 <br>
|
||||||
|
* 等价SQL: TRUNCATE TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
* @param node 过滤条件
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
public <T> int clearTable(final Class<T> clazz, final FilterNode node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空表 <br>
|
||||||
|
* 等价SQL: TRUNCATE TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
* @param node 过滤条件
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
public <T> CompletableFuture<Integer> clearTableAsync(final Class<T> clazz, final FilterNode node);
|
||||||
|
|
||||||
|
//------------------------dropAsync---------------------------
|
||||||
|
/**
|
||||||
|
* 删除表 <br>
|
||||||
|
* 等价SQL: DROP TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
public <T> int dropTable(final Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除表 <br>
|
||||||
|
* 等价SQL: DROP TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
public <T> CompletableFuture<Integer> dropTableAsync(final Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除表 <br>
|
||||||
|
* 等价SQL: DROP TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
* @param node 过滤条件
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
public <T> int dropTable(final Class<T> clazz, final FilterNode node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除表 <br>
|
||||||
|
* 等价SQL: DROP TABLE {table}<br>
|
||||||
|
*
|
||||||
|
* @param <T> Entity泛型
|
||||||
|
* @param clazz Entity类
|
||||||
|
* @param node 过滤条件
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
public <T> CompletableFuture<Integer> dropTableAsync(final Class<T> clazz, final FilterNode node);
|
||||||
|
|
||||||
//------------------------updateAsync---------------------------
|
//------------------------updateAsync---------------------------
|
||||||
/**
|
/**
|
||||||
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
@@ -159,12 +310,12 @@ public interface DataSource {
|
|||||||
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
||||||
* ··· <br>
|
* ··· <br>
|
||||||
*
|
*
|
||||||
* @param <T> 泛型
|
* @param <T> 泛型
|
||||||
* @param values Entity对象
|
* @param entitys Entity对象
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int update(final T... values);
|
public <T> int update(final T... entitys);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
@@ -173,12 +324,80 @@ public interface DataSource {
|
|||||||
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
||||||
* ··· <br>
|
* ··· <br>
|
||||||
*
|
*
|
||||||
* @param <T> 泛型
|
* @param <T> 泛型
|
||||||
* @param values Entity对象
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
default <T> int update(final Collection<T> entitys) {
|
||||||
|
if (entitys == null || entitys.isEmpty()) return 0;
|
||||||
|
return update(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1} <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
||||||
|
* ··· <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数
|
||||||
|
*/
|
||||||
|
default <T> int update(final Stream<T> entitys) {
|
||||||
|
if (entitys == null) return 0;
|
||||||
|
return update(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1} <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
||||||
|
* ··· <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> updateAsync(final T... values);
|
public <T> CompletableFuture<Integer> updateAsync(final T... entitys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1} <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
||||||
|
* ··· <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
default <T> CompletableFuture<Integer> updateAsync(final Collection<T> entitys) {
|
||||||
|
if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0);
|
||||||
|
return updateAsync(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新记录, 多对象必须是同一个Entity类且必须在同一张表中 <br>
|
||||||
|
* 等价SQL: <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1} <br>
|
||||||
|
* UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2} <br>
|
||||||
|
* ··· <br>
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param entitys Entity对象
|
||||||
|
*
|
||||||
|
* @return 影响的记录条数CompletableFuture
|
||||||
|
*/
|
||||||
|
default <T> CompletableFuture<Integer> updateAsync(final Stream<T> entitys) {
|
||||||
|
if (entitys == null) return CompletableFuture.completedFuture(0);
|
||||||
|
return updateAsync(entitys.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新单个记录的单个字段 <br>
|
* 更新单个记录的单个字段 <br>
|
||||||
@@ -187,13 +406,13 @@ public interface DataSource {
|
|||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param id 主键
|
* @param pk 主键
|
||||||
* @param column 待更新的字段名
|
* @param column 待更新的字段名
|
||||||
* @param value 更新值
|
* @param value 更新值
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value);
|
public <T> int updateColumn(final Class<T> clazz, final Serializable pk, final String column, final Serializable value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新单个记录的单个字段 <br>
|
* 更新单个记录的单个字段 <br>
|
||||||
@@ -202,13 +421,13 @@ public interface DataSource {
|
|||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param id 主键
|
* @param pk 主键
|
||||||
* @param column 待更新的字段名
|
* @param column 待更新的字段名
|
||||||
* @param value 更新值
|
* @param value 更新值
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable id, final String column, final Serializable value);
|
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable pk, final String column, final Serializable value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新符合过滤条件记录的单个字段 <br>
|
* 更新符合过滤条件记录的单个字段 <br>
|
||||||
@@ -247,12 +466,12 @@ public interface DataSource {
|
|||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param id 主键
|
* @param pk 主键
|
||||||
* @param values 更新字段
|
* @param values 更新字段
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values);
|
public <T> int updateColumn(final Class<T> clazz, final Serializable pk, final ColumnValue... values);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新指定主键值记录的部分字段 <br>
|
* 更新指定主键值记录的部分字段 <br>
|
||||||
@@ -261,12 +480,12 @@ public interface DataSource {
|
|||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param id 主键
|
* @param pk 主键
|
||||||
* @param values 更新字段
|
* @param values 更新字段
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable id, final ColumnValue... values);
|
public <T> CompletableFuture<Integer> updateColumnAsync(final Class<T> clazz, final Serializable pk, final ColumnValue... values);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新符合过滤条件记录的部分字段 <br>
|
* 更新符合过滤条件记录的部分字段 <br>
|
||||||
@@ -336,12 +555,12 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param columns 需更新的字段名
|
* @param columns 需更新的字段名
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int updateColumn(final T bean, final String... columns);
|
public <T> int updateColumn(final T entity, final String... columns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新单个记录的指定字段 <br>
|
* 更新单个记录的指定字段 <br>
|
||||||
@@ -349,12 +568,12 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param columns 需更新的字段名
|
* @param columns 需更新的字段名
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final String... columns);
|
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final String... columns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新符合过滤条件记录的指定字段 <br>
|
* 更新符合过滤条件记录的指定字段 <br>
|
||||||
@@ -362,13 +581,13 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param node 过滤条件
|
* @param node 过滤条件
|
||||||
* @param columns 需更新的字段名
|
* @param columns 需更新的字段名
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int updateColumn(final T bean, final FilterNode node, final String... columns);
|
public <T> int updateColumn(final T entity, final FilterNode node, final String... columns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新符合过滤条件记录的指定字段 <br>
|
* 更新符合过滤条件记录的指定字段 <br>
|
||||||
@@ -376,13 +595,13 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param node 过滤条件
|
* @param node 过滤条件
|
||||||
* @param columns 需更新的字段名
|
* @param columns 需更新的字段名
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final FilterNode node, final String... columns);
|
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final FilterNode node, final String... columns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新单个记录的指定字段 <br>
|
* 更新单个记录的指定字段 <br>
|
||||||
@@ -390,12 +609,12 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param selects 指定字段
|
* @param selects 指定字段
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int updateColumn(final T bean, final SelectColumn selects);
|
public <T> int updateColumn(final T entity, final SelectColumn selects);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新单个记录的指定字段 <br>
|
* 更新单个记录的指定字段 <br>
|
||||||
@@ -403,12 +622,12 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param selects 指定字段
|
* @param selects 指定字段
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final SelectColumn selects);
|
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final SelectColumn selects);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新符合过滤条件记录的指定字段 <br>
|
* 更新符合过滤条件记录的指定字段 <br>
|
||||||
@@ -416,13 +635,13 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param node 过滤条件
|
* @param node 过滤条件
|
||||||
* @param selects 指定字段
|
* @param selects 指定字段
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数
|
* @return 影响的记录条数
|
||||||
*/
|
*/
|
||||||
public <T> int updateColumn(final T bean, final FilterNode node, final SelectColumn selects);
|
public <T> int updateColumn(final T entity, final FilterNode node, final SelectColumn selects);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新符合过滤条件记录的指定字段 <br>
|
* 更新符合过滤条件记录的指定字段 <br>
|
||||||
@@ -430,13 +649,13 @@ public interface DataSource {
|
|||||||
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
* 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node} <br>
|
||||||
*
|
*
|
||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param bean 待更新的Entity对象
|
* @param entity 待更新的Entity对象
|
||||||
* @param node 过滤条件
|
* @param node 过滤条件
|
||||||
* @param selects 指定字段
|
* @param selects 指定字段
|
||||||
*
|
*
|
||||||
* @return 影响的记录条数CompletableFuture
|
* @return 影响的记录条数CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<Integer> updateColumnAsync(final T bean, final FilterNode node, final SelectColumn selects);
|
public <T> CompletableFuture<Integer> updateColumnAsync(final T entity, final FilterNode node, final SelectColumn selects);
|
||||||
|
|
||||||
//############################################# 查询接口 #############################################
|
//############################################# 查询接口 #############################################
|
||||||
//-----------------------getXXXXResult-----------------------------
|
//-----------------------getXXXXResult-----------------------------
|
||||||
@@ -856,11 +1075,11 @@ public interface DataSource {
|
|||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return Entity对象
|
* @return Entity对象
|
||||||
*/
|
*/
|
||||||
public <T> T find(final Class<T> clazz, final String column, final Serializable key);
|
public <T> T find(final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
|
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
|
||||||
@@ -869,11 +1088,11 @@ public interface DataSource {
|
|||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return Entity对象CompletableFuture
|
* @return Entity对象CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<T> findAsync(final Class<T> clazz, final String column, final Serializable key);
|
public <T> CompletableFuture<T> findAsync(final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
|
* 获取符合过滤条件单个记录, 返回null表示不存在值 <br>
|
||||||
@@ -1219,11 +1438,11 @@ public interface DataSource {
|
|||||||
* @param selectedColumn 指定字段
|
* @param selectedColumn 指定字段
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return 字段值的集合
|
* @return 字段值的集合
|
||||||
*/
|
*/
|
||||||
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
|
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的某个字段Set集合 <br>
|
* 查询符合过滤条件记录的某个字段Set集合 <br>
|
||||||
@@ -1234,11 +1453,11 @@ public interface DataSource {
|
|||||||
* @param selectedColumn 指定字段
|
* @param selectedColumn 指定字段
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return 字段值的集合CompletableFuture
|
* @return 字段值的集合CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T, V extends Serializable> CompletableFuture<HashSet<V>> queryColumnSetAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
|
public <T, V extends Serializable> CompletableFuture<HashSet<V>> queryColumnSetAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的某个字段Set集合 <br>
|
* 查询符合过滤条件记录的某个字段Set集合 <br>
|
||||||
@@ -1305,11 +1524,11 @@ public interface DataSource {
|
|||||||
* @param selectedColumn 指定字段
|
* @param selectedColumn 指定字段
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return 字段值的集合
|
* @return 字段值的集合
|
||||||
*/
|
*/
|
||||||
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
|
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的某个字段List集合 <br>
|
* 查询符合过滤条件记录的某个字段List集合 <br>
|
||||||
@@ -1320,11 +1539,11 @@ public interface DataSource {
|
|||||||
* @param selectedColumn 指定字段
|
* @param selectedColumn 指定字段
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return 字段值的集合CompletableFuture
|
* @return 字段值的集合CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T, V extends Serializable> CompletableFuture<List<V>> queryColumnListAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
|
public <T, V extends Serializable> CompletableFuture<List<V>> queryColumnListAsync(final String selectedColumn, final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的某个字段List集合 <br>
|
* 查询符合过滤条件记录的某个字段List集合 <br>
|
||||||
@@ -1671,11 +1890,11 @@ public interface DataSource {
|
|||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return Entity的集合
|
* @return Entity的集合
|
||||||
*/
|
*/
|
||||||
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key);
|
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的List集合 <br>
|
* 查询符合过滤条件记录的List集合 <br>
|
||||||
@@ -1684,11 +1903,11 @@ public interface DataSource {
|
|||||||
* @param <T> Entity泛型
|
* @param <T> Entity泛型
|
||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return Entity的集合CompletableFuture
|
* @return Entity的集合CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final String column, final Serializable key);
|
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的List集合 <br>
|
* 查询符合过滤条件记录的List集合 <br>
|
||||||
@@ -1824,11 +2043,11 @@ public interface DataSource {
|
|||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param flipper 翻页对象
|
* @param flipper 翻页对象
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return Entity的集合
|
* @return Entity的集合
|
||||||
*/
|
*/
|
||||||
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key);
|
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的List集合 <br>
|
* 查询符合过滤条件记录的List集合 <br>
|
||||||
@@ -1838,11 +2057,11 @@ public interface DataSource {
|
|||||||
* @param clazz Entity类
|
* @param clazz Entity类
|
||||||
* @param flipper 翻页对象
|
* @param flipper 翻页对象
|
||||||
* @param column 过滤字段名
|
* @param column 过滤字段名
|
||||||
* @param key 过滤字段值
|
* @param colval 过滤字段值
|
||||||
*
|
*
|
||||||
* @return Entity的集合CompletableFuture
|
* @return Entity的集合CompletableFuture
|
||||||
*/
|
*/
|
||||||
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key);
|
public <T> CompletableFuture<List<T>> queryListAsync(final Class<T> clazz, final Flipper flipper, final String column, final Serializable colval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询符合过滤条件记录的List集合 <br>
|
* 查询符合过滤条件记录的List集合 <br>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.lang.reflect.Constructor;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.xml.stream.*;
|
import javax.xml.stream.*;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -56,55 +57,28 @@ public final class DataSources {
|
|||||||
private DataSources() {
|
private DataSources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSource createDataSource2(final String unitName, Properties prop) throws IOException {
|
public static DataSource createDataSource(final String unitName, final AnyValue conf) throws IOException {
|
||||||
return new DataJdbcSource(unitName, null, prop, prop);
|
Properties prop = new Properties();
|
||||||
}
|
AnyValue[] confs = conf.getAnyValues("property");
|
||||||
|
if (confs != null) {
|
||||||
public static DataSource createDataSource2(final String unitName, Properties readprop, Properties writeprop) throws IOException {
|
for (AnyValue itemConf : confs) {
|
||||||
return new DataJdbcSource(unitName, null, readprop, writeprop);
|
String name = itemConf.getValue("name");
|
||||||
}
|
String value = itemConf.getValue("value");
|
||||||
|
if (name != null && value != null) prop.put(name, value);
|
||||||
public static DataSource createDataSource(final String unitName) throws IOException {
|
|
||||||
return createDataSource(unitName, System.getProperty(DATASOURCE_CONFPATH) == null
|
|
||||||
? DataJdbcSource.class.getResource("/META-INF/persistence.xml")
|
|
||||||
: new File(System.getProperty(DATASOURCE_CONFPATH)).toURI().toURL());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DataSource createDataSource(final String unitName, URL persistxml) throws IOException {
|
|
||||||
if (persistxml == null) persistxml = DataSources.class.getResource("/persistence.xml");
|
|
||||||
InputStream in = persistxml == null ? null : persistxml.openStream();
|
|
||||||
if (in == null) return null;
|
|
||||||
Map<String, Properties> map = loadPersistenceXml(in);
|
|
||||||
Properties readprop = null;
|
|
||||||
Properties writeprop = null;
|
|
||||||
if (unitName != null) {
|
|
||||||
readprop = map.get(unitName);
|
|
||||||
writeprop = readprop;
|
|
||||||
if (readprop == null) {
|
|
||||||
readprop = map.get(unitName + ".read");
|
|
||||||
writeprop = map.get(unitName + ".write");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((unitName == null || unitName.isEmpty()) || readprop == null) {
|
return createDataSource(unitName, prop, prop);
|
||||||
String key = null;
|
}
|
||||||
for (Map.Entry<String, Properties> en : map.entrySet()) {
|
|
||||||
key = en.getKey();
|
|
||||||
readprop = en.getValue();
|
|
||||||
writeprop = readprop;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (key != null && (key.endsWith(".read") || key.endsWith(".write"))) {
|
|
||||||
if (key.endsWith(".read")) {
|
|
||||||
writeprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".write");
|
|
||||||
} else {
|
|
||||||
readprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".read");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (readprop == null) throw new IOException("Cannot find (resource.name = '" + unitName + "') DataSource");
|
|
||||||
if (writeprop == null) writeprop = readprop;
|
|
||||||
if (readprop.getProperty(JDBC_URL, "").startsWith("memory:source")) return new DataMemorySource(unitName, persistxml, readprop, writeprop);
|
|
||||||
|
|
||||||
|
public static DataSource createDataSource(final String unitName, Properties prop) throws IOException {
|
||||||
|
return createDataSource(unitName, prop, prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataSource createDataSource(final String unitName, Properties readprop, Properties writeprop) throws IOException {
|
||||||
|
return createDataSource(unitName, null, readprop, writeprop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataSource createDataSource(final String unitName, URL persistxml, Properties readprop, Properties writeprop) throws IOException {
|
||||||
String impl = readprop.getProperty(JDBC_DATASOURCE_CLASS, DataJdbcSource.class.getName());
|
String impl = readprop.getProperty(JDBC_DATASOURCE_CLASS, DataJdbcSource.class.getName());
|
||||||
if (DataJdbcSource.class.getName().equals(impl)) {
|
if (DataJdbcSource.class.getName().equals(impl)) {
|
||||||
try {
|
try {
|
||||||
@@ -162,6 +136,50 @@ public final class DataSources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DataSource createDataSource(final String unitName) throws IOException {
|
||||||
|
return createDataSource(unitName, System.getProperty(DATASOURCE_CONFPATH) == null
|
||||||
|
? DataJdbcSource.class.getResource("/META-INF/persistence.xml")
|
||||||
|
: new File(System.getProperty(DATASOURCE_CONFPATH)).toURI().toURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataSource createDataSource(final String unitName, URL persistxml) throws IOException {
|
||||||
|
if (persistxml == null) persistxml = DataSources.class.getResource("/persistence.xml");
|
||||||
|
InputStream in = persistxml == null ? null : persistxml.openStream();
|
||||||
|
if (in == null) return null;
|
||||||
|
Map<String, Properties> map = loadPersistenceXml(in);
|
||||||
|
Properties readprop = null;
|
||||||
|
Properties writeprop = null;
|
||||||
|
if (unitName != null) {
|
||||||
|
readprop = map.get(unitName);
|
||||||
|
writeprop = readprop;
|
||||||
|
if (readprop == null) {
|
||||||
|
readprop = map.get(unitName + ".read");
|
||||||
|
writeprop = map.get(unitName + ".write");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unitName == null || unitName.isEmpty()) {
|
||||||
|
String key = null;
|
||||||
|
for (Map.Entry<String, Properties> en : map.entrySet()) {
|
||||||
|
key = en.getKey();
|
||||||
|
readprop = en.getValue();
|
||||||
|
writeprop = readprop;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (key != null && (key.endsWith(".read") || key.endsWith(".write"))) {
|
||||||
|
if (key.endsWith(".read")) {
|
||||||
|
writeprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".write");
|
||||||
|
} else {
|
||||||
|
readprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".read");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (readprop == null) throw new IOException("Cannot find (resource.name = '" + unitName + "') DataSource");
|
||||||
|
if (writeprop == null) writeprop = readprop;
|
||||||
|
if (readprop.getProperty(JDBC_URL, "").startsWith("memory:source")) return new DataMemorySource(unitName, persistxml, readprop, writeprop);
|
||||||
|
|
||||||
|
return createDataSource(unitName, readprop, writeprop);
|
||||||
|
}
|
||||||
|
|
||||||
public static Map<String, Properties> loadPersistenceXml(final InputStream in0) {
|
public static Map<String, Properties> loadPersistenceXml(final InputStream in0) {
|
||||||
final Map<String, Properties> map = new LinkedHashMap();
|
final Map<String, Properties> map = new LinkedHashMap();
|
||||||
Properties result = new Properties();
|
Properties result = new Properties();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user