117 Commits
1.9.6 ... 1.9.9

Author SHA1 Message Date
Redkale
a78c2145e6 2018-12-24 17:16:39 +08:00
Redkale
ee20a34a70 2018-12-24 14:52:05 +08:00
Redkale
33bd80c572 2018-12-22 15:16:00 +08:00
Redkale
031309b105 2018-12-22 15:08:56 +08:00
Redkale
bcbd981a9b 2018-12-21 10:55:20 +08:00
Redkale
b7ce390c33 WebServlet.value带.不视为正则表达式 2018-12-21 10:38:37 +08:00
Redkale
c9d099c694 2018-12-20 17:22:16 +08:00
Redkale
fcca0329c6 2018-12-20 13:55:46 +08:00
Redkale
c82c0bc680 2018-12-20 11:51:12 +08:00
Redkale
2921478a0a 2018-12-20 11:38:11 +08:00
Redkale
61a5420d48 兼容泛型嵌套 2018-12-19 18:38:28 +08:00
Redkale
702ab6ef6e 2018-12-19 16:03:11 +08:00
Redkale
2576e71a7d 2018-12-19 11:33:08 +08:00
Redkale
0d0bd78213 2018-12-18 15:20:13 +08:00
Redkale
8d9fa8f9cf 2018-12-18 14:15:27 +08:00
Redkale
25eaf6e353 AsyncConnection接口大变动 2018-12-18 14:04:49 +08:00
Redkale
8afcaa0b34 2018-12-18 09:41:20 +08:00
Redkale
1824f8150c 2018-12-17 10:57:49 +08:00
Redkale
2f89778fd6 2018-12-17 10:56:00 +08:00
Redkale
f9d250b43c 2018-12-17 10:29:23 +08:00
Redkale
3a3c09d8aa 2018-12-15 15:07:46 +08:00
Redkale
09a0d4f9e2 2018-12-15 15:06:24 +08:00
Redkale
3bba781183 WATCH服务增加功能:更改Server的监听地址和端口 2018-12-13 13:47:44 +08:00
Redkale
6426f8fe91 2018-12-11 19:46:31 +08:00
Redkale
5906594148 2018-12-11 18:58:15 +08:00
Redkale
1b188c863c 2018-12-10 19:51:31 +08:00
Redkale
087b4cb571 2018-12-10 19:47:26 +08:00
Redkale
c9496b6231 application.xml中source节点兼容DataJdbcSource 2018-12-10 19:44:56 +08:00
Redkale
60d95d7628 2018-12-06 21:29:55 +08:00
Redkale
dd9e7e77b5 2018-12-06 21:06:21 +08:00
Redkale
50c9363876 2018-12-05 17:59:56 +08:00
Redkale
938e357745 2018-12-03 09:04:27 +08:00
Redkale
08ee51f8ab 2018-12-01 14:22:30 +08:00
Redkale
40ae555645 2018-11-29 14:09:18 +08:00
Redkale
33f89264a6 2018-11-29 13:54:14 +08:00
Redkale
e4ea20cc5f 2018-11-28 14:33:55 +08:00
Redkale
045b7db1af 修复JsonConvert的""空字符串转换对象抛异常的BUG 2018-11-28 14:23:10 +08:00
Redkale
676c1b5d21 修复JsonConvert的""空字符串转换对象抛异常的BUG 2018-11-28 14:22:00 +08:00
Redkale
e4319246b8 2018-11-28 14:04:07 +08:00
Redkale
32d8515bf4 DataSource增加部分JSON功能 2018-11-28 11:17:55 +08:00
Redkale
d7e7113201 Sncp的部分Attribute.type()改为genericType方法 2018-11-28 09:18:12 +08:00
Redkale
9493aa43a7 Attribute增加genericType方法 2018-11-28 09:12:58 +08:00
Redkale
d07c55b831 【不兼容】BSON格式升级,兼容子类数据转父类对象 2018-11-27 15:10:19 +08:00
Redkale
47dab88d72 调整Convert部分内部接口 2018-11-27 14:10:58 +08:00
Redkale
9e553aeff6 修复JsonReader.readSmallString() BUG 2018-11-27 11:48:50 +08:00
Redkale
ed8e754557 兼容ColumnValue...含null的情况 2018-11-24 14:20:06 +08:00
Redkale
651dc3df2a 还原 2018-11-22 14:47:58 +08:00
Redkale
84e5bc3437 2018-11-22 14:46:55 +08:00
Redkale
64fd0176ac 兼容手动new XXXService字段inject时抛异常 2018-11-22 14:45:24 +08:00
Redkale
c1f3115d4e 2018-11-20 10:55:09 +08:00
Redkale
1c70834760 2018-11-19 17:33:33 +08:00
Redkale
7c901731bc Bson的skipValue方法支持部分常规Collection<JavaBean>、Map<String, JavaBean>字段类型 2018-11-19 15:32:24 +08:00
Redkale
2b2d53e515 Bson的skipValue方法支持部分常规Collection、Map字段类型 2018-11-19 15:14:48 +08:00
Redkale
be051ecf45 Redkale 1.9.9 开始 2018-11-19 15:12:20 +08:00
Redkale
18534eb654 2018-11-08 16:08:48 +08:00
Redkale
a5a926fd94 FilterNode、FilterJoinNode增加copy方法 2018-10-18 14:47:07 +08:00
Redkale
0cb9f2cad3 2018-10-17 08:18:23 +08:00
Redkale
98209cc82e 修改WebSocketNode.existsWebSocket的实现 2018-10-10 14:03:54 +08:00
Redkale
1879afa6a4 2018-10-09 16:34:35 +08:00
Redkale
4a6404dfec 2018-09-27 09:54:42 +08:00
Redkale
0fa1c4a08f 修复WebSocket中Connection重复的bug 2018-09-27 09:51:44 +08:00
Redkale
573d7c5776 修复Rest.createRestWebSocketServlet空指针bug 2018-09-26 17:23:19 +08:00
Redkale
c56c9bf260 Redkale 1.9.8 开始 2018-09-26 17:21:33 +08:00
Redkale
387865789f 2018-09-20 16:03:33 +08:00
Redkale
03fcf43a89 2018-09-19 11:11:59 +08:00
Redkale
df8090813a 2018-09-12 12:11:19 +08:00
Redkale
849b29d00f CacheSource的增删改查操作增加Type参数 2018-09-12 12:04:59 +08:00
Redkale
4b7f65e1c4 2018-09-11 14:29:42 +08:00
Redkale
4545d81e50 2018-09-11 11:12:43 +08:00
Redkale
1ac5f060a4 增加WebSocketAction功能 2018-09-11 09:13:19 +08:00
Redkale
7e1ff8e315 2018-09-10 17:23:23 +08:00
Redkale
4e0c1fee97 2018-09-10 14:02:26 +08:00
Redkale
0b38f23f2d 2018-09-10 14:01:56 +08:00
Redkale
98ea6861c1 2018-09-10 10:44:03 +08:00
Redkale
c07b628ea1 FilterNode增加readonly属性 2018-09-07 10:21:48 +08:00
Redkale
b1b979c0b5 优化Rest.createRestServlet减少preInit的耗时 2018-09-07 09:20:52 +08:00
Redkale
35b708b01d 2018-09-07 08:50:20 +08:00
Redkale
229ae0d44f 2018-09-06 18:17:11 +08:00
Redkale
7d6897fa36 2018-09-06 14:33:53 +08:00
Redkale
5851093590 2018-09-05 16:58:19 +08:00
Redkale
4646c1d1f0 2018-09-05 16:57:09 +08:00
Redkale
f3763dbf72 2018-09-05 16:41:44 +08:00
Redkale
6a8c60ec78 优化NodeHttpServer.loadRestServlet 2018-09-05 16:15:21 +08:00
Redkale
ae437fd5d6 优化Rest.createRestServlet 2018-09-05 15:53:54 +08:00
Redkale
7251c984c8 修复FilterNode.findValue的bug 2018-09-05 11:00:47 +08:00
Redkale
ec449220eb 2018-09-05 09:49:20 +08:00
Redkale
78265944f0 2018-09-05 09:23:41 +08:00
Redkale
d2791f6d1b 2018-09-05 08:29:58 +08:00
Redkale
d525d2664b 2018-08-31 10:39:43 +08:00
Redkale
a4ccea91ad 修复FilterJoinNode.any方法bug 2018-08-29 16:06:41 +08:00
Redkale
750da161eb 增强HttpUserType的类型校验 2018-08-28 10:18:27 +08:00
Redkale
ac50312f0b 2018-08-27 18:28:56 +08:00
Redkale
8d44d48072 2018-08-27 18:26:16 +08:00
Redkale
6c2baa1708 增加RestConvertCoder功能 2018-08-27 18:25:08 +08:00
Redkale
4525cfe594 2018-08-27 12:36:35 +08:00
Redkale
921f96c975 优化toBuffers方法 2018-08-27 12:29:59 +08:00
Redkale
29ce57d3af BsonWriter.toBuffers存在并发问题 2018-08-27 12:07:45 +08:00
Redkale
2ca1e6305c 修改HttpResponse.finish(byte[]) 2018-08-27 11:55:36 +08:00
Redkale
827b404a57 Update application.xml 2018-08-25 13:35:48 +08:00
Redkale
83569142c1 2018-08-25 13:12:24 +08:00
Redkale
2da0faacc3 2018-08-24 16:24:58 +08:00
Redkale
cf51bee2cc 2018-08-24 16:07:19 +08:00
Redkale
0dd55dc947 2018-08-24 16:04:49 +08:00
Redkale
620fa0430c ClassFilter输出更详细日志 2018-08-23 19:54:47 +08:00
Redkale
d053590257 增加JDK9+环境下显示进程PID功能 2018-08-23 19:28:20 +08:00
Redkale
684af3de61 application.xml的properties值支持${APP_HOME} 2018-08-23 09:59:14 +08:00
Redkale
6c6e26ed0b 2018-08-22 10:37:49 +08:00
Redkale
4a05bfbd08 2018-08-22 10:34:48 +08:00
Redkale
787dc7b32f 2018-08-22 10:03:20 +08:00
Redkale
85a1f99f6e 2018-08-22 09:42:51 +08:00
Redkale
4fe8a1199e 修复CollectionDecoder的creator指定错误的bug 2018-08-22 09:30:11 +08:00
Redkale
7312dbc4c5 增加H2数据库的支持 2018-08-21 10:06:05 +08:00
Redkale
cfecfabc92 createRestServlet兼容throws IOException和RuntimeException的子类 2018-08-20 17:28:34 +08:00
Redkale
587160c5fe Redkale 1.9.7 开始 2018-08-20 17:23:13 +08:00
Redkale
ee7fe3ed33 2018-08-20 16:49:39 +08:00
Redkale
47d4a6cc29 2018-08-20 14:42:16 +08:00
Redkale
c1e4763369 2018-08-20 14:28:02 +08:00
122 changed files with 3129 additions and 2044 deletions

View File

@@ -14,7 +14,7 @@ fi
cd "$APP_HOME" cd "$APP_HOME"
./bin/shutdown.sh "$APP_HOME"/bin/shutdown.sh
./bin/start.sh "$APP_HOME"/bin/start.sh

View File

@@ -1,7 +1,7 @@
@ECHO OFF @ECHO OFF
SET APP_HOME=%~dp0 SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

@@ -24,5 +24,5 @@ done
export CLASSPATH=$CLASSPATH:$lib export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME" echo "$APP_HOME"
nohup java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application > "$APP_HOME"/log.out & nohup java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application > "$APP_HOME"/logs.out &

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<application port="5050"> <application port="2121">
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml --> <!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
@@ -8,7 +8,7 @@
</resources> </resources>
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root"> <server protocol="HTTP" port="6060">
<request> <request>
<remoteaddr value="request.headers.X-RemoteAddress"/> <remoteaddr value="request.headers.X-RemoteAddress"/>

View File

@@ -16,7 +16,6 @@
<shared-cache-mode>ALL</shared-cache-mode> <shared-cache-mode>ALL</shared-cache-mode>
<properties> <properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="javax.persistence.jdbc.user" value="system"/> <property name="javax.persistence.jdbc.user" value="system"/>
<property name="javax.persistence.jdbc.password" value="1234"/> <property name="javax.persistence.jdbc.password" value="1234"/>
</properties> </properties>
@@ -25,8 +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&amp;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.driver" value="com.mysql.jdbc.Driver"/>
<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>

View File

@@ -63,6 +63,7 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.5.1</version>
<configuration> <configuration>
<compilerArgument>-parameters</compilerArgument>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<compilerArguments> <compilerArguments>
<verbose /> <verbose />

View File

@@ -125,7 +125,7 @@
aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive
readTimeoutSeconds: 读操作超时秒数, 默认0 表示永久不超时 readTimeoutSeconds: 读操作超时秒数, 默认0 表示永久不超时
writeTimeoutSeconds: 写操作超时秒数, 默认0 表示永久不超时 writeTimeoutSeconds: 写操作超时秒数, 默认0 表示永久不超时
netimpl: ProtocolServer的实现类。TCP情况下值可以是aio或nio默认值为aioUDP情况下值可以是bio默认值为bio netimpl: ProtocolServer的实现类。TCP情况下值可以是aio或nio默认值为aioUDP情况下值可以是bio默认值为bio
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null
--> -->
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib=""> <server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">

View File

@@ -11,8 +11,8 @@ javax.level = INFO
com.sun.level = INFO com.sun.level = INFO
#java.util.logging.FileHandler.level = FINE #java.util.logging.FileHandler.level = FINE
#10M
java.util.logging.FileHandler.limit = 10485760 java.util.logging.FileHandler.limit = 20M
java.util.logging.FileHandler.count = 100 java.util.logging.FileHandler.count = 100
java.util.logging.FileHandler.encoding = UTF-8 java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log

View File

@@ -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"/>
@@ -20,12 +20,15 @@
org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource
org.postgresql.Driver —————— org.postgresql.ds.PGConnectionPoolDataSource org.postgresql.Driver —————— org.postgresql.ds.PGConnectionPoolDataSource
com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
com.mysql.cj.jdbc.Driver —————— com.mysql.cj.jdbc.MysqlConnectionPoolDataSource
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
org.h2.Driver —————— org.h2.jdbcx.JdbcDataSource
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource 因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
并且如果JDBC驱动是以上几个版本javax.persistence.jdbc.driver属性都可以省略Redkale会根据javax.persistence.jdbc.url的值来识别驱动 并且如果JDBC驱动是以上几个版本javax.persistence.jdbc.driver属性都可以省略Redkale会根据javax.persistence.jdbc.url的值来识别驱动
-->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.source" value="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"/>
-->
<property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/> <property name="javax.persistence.jdbc.password" value="123456"/>
@@ -47,7 +50,6 @@
<properties> <properties>
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 --> <!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/> <property name="javax.persistence.jdbc.password" value="123456"/>
</properties> </properties>

View File

@@ -10,7 +10,6 @@ module org.redkale {
requires java.logging; requires java.logging;
requires java.xml; requires java.xml;
requires java.sql; requires java.sql;
requires java.sql.rowset;
requires jdk.unsupported; //sun.misc.Unsafe requires jdk.unsupported; //sun.misc.Unsafe

View File

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

View File

@@ -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;
@@ -171,7 +171,6 @@ public final class Application {
this.singletonrun = singletonrun; this.singletonrun = singletonrun;
this.config = config; this.config = config;
System.setProperty("redkale.version", Redkale.getDotedVersion()); System.setProperty("redkale.version", Redkale.getDotedVersion());
System.setProperty("sun.nio.ch.maxCompletionHandlersOnStack", String.valueOf(Math.max(256, Runtime.getRuntime().availableProcessors() * 8)));
final File root = new File(System.getProperty(RESNAME_APP_HOME)); final File root = new File(System.getProperty(RESNAME_APP_HOME));
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime); this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
@@ -182,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);
@@ -210,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('\\', '/');
@@ -376,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() {
@@ -389,7 +388,6 @@ public final class Application {
} }
public void init() throws Exception { public void init() throws Exception {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + Runtime.getRuntime().availableProcessors() * 4);
System.setProperty("net.transport.poolmaxconns", "100"); System.setProperty("net.transport.poolmaxconns", "100");
System.setProperty("net.transport.pinginterval", "30"); System.setProperty("net.transport.pinginterval", "30");
System.setProperty("net.transport.checkinterval", "30"); System.setProperty("net.transport.checkinterval", "30");
@@ -400,11 +398,19 @@ 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());
logger.log(Level.INFO, "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath + "\r\n" + RESNAME_APP_CONF + " = " + confpath); String pidstr = "";
try { //JDK 9+
Class phclass = Class.forName("java.lang.ProcessHandle");
Object phobj = phclass.getMethod("current").invoke(null);
Object pid = phclass.getMethod("pid").invoke(phobj);
pidstr = "APP_PID = " + pid + "\r\n";
} catch (Throwable t) {
}
logger.log(Level.INFO, pidstr + "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath + "\r\n" + RESNAME_APP_CONF + " = " + confpath);
String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath); String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? confpath : (lib + ";" + confpath); lib = lib.isEmpty() ? confpath : (lib + ";" + confpath);
Server.loadLib(classLoader, logger, lib); Server.loadLib(classLoader, logger, lib);
@@ -419,13 +425,13 @@ 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);
ps.load(in); ps.load(in);
in.close(); in.close();
ps.forEach((x, y) -> resourceFactory.register("property." + x, y)); ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath)));
} }
} }
} }
@@ -433,6 +439,7 @@ public final class Application {
String name = prop.getValue("name"); String name = prop.getValue("name");
String value = prop.getValue("value"); String value = prop.getValue("value");
if (name == null || value == null) continue; if (name == null || value == null) continue;
value = value.replace("${APP_HOME}", homepath);
if (name.startsWith("system.property.")) { if (name.startsWith("system.property.")) {
System.setProperty(name.substring("system.property.".length()), value); System.setProperty(name.substring("system.property.".length()), value);
} else if (name.startsWith("mimetype.property.")) { } else if (name.startsWith("mimetype.property.")) {
@@ -460,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);
@@ -552,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();

View File

@@ -7,7 +7,7 @@ package org.redkale.boot;
import java.io.*; import java.io.*;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.lang.reflect.*; 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.*;
@@ -30,7 +30,7 @@ public final class ClassFilter<T> {
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象 private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
private static final boolean finer = logger.isLoggable(Level.FINER); //日志级别 private static final boolean finest = logger.isLoggable(Level.FINEST); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果 private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
@@ -136,10 +136,11 @@ public final class ClassFilter<T> {
* *
* @param property AnyValue * @param property AnyValue
* @param clazzname String * @param clazzname String
* @param url URL
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final void filter(AnyValue property, String clazzname) { public final void filter(AnyValue property, String clazzname, URL url) {
filter(property, clazzname, true); filter(property, clazzname, true, url);
} }
/** /**
@@ -150,6 +151,18 @@ public final class ClassFilter<T> {
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略 * @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
*/ */
public final void filter(AnyValue property, String clazzname, boolean autoscan) { public final void filter(AnyValue property, String clazzname, boolean autoscan) {
filter(property, clazzname, autoscan, null);
}
/**
* 过滤指定的class
*
* @param property application.xml中对应class节点下的property属性项
* @param clazzname class名称
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
* @param url URL
*/
public final void filter(AnyValue property, String clazzname, boolean autoscan, URL url) {
boolean r = accept0(property, clazzname); boolean r = accept0(property, clazzname);
ClassFilter cf = r ? this : null; ClassFilter cf = r ? this : null;
if (r && ands != null) { if (r && ands != null) {
@@ -165,7 +178,7 @@ public final class ClassFilter<T> {
} }
} }
} }
if (cf == null || clazzname.startsWith("sun.")) return; if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) return;
try { try {
Class clazz = classLoader.loadClass(clazzname); Class clazz = classLoader.loadClass(clazzname);
if (!cf.accept(property, clazz, autoscan)) return; if (!cf.accept(property, clazz, autoscan)) return;
@@ -189,9 +202,10 @@ public final class ClassFilter<T> {
entrys.add(new FilterEntry(clazz, autoscan, false, property)); entrys.add(new FilterEntry(clazz, autoscan, false, property));
} }
} catch (Throwable cfe) { } catch (Throwable cfe) {
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.") if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) { && !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe); && (!(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);
} }
} }
} }
@@ -347,6 +361,7 @@ public final class ClassFilter<T> {
public void setPrivilegeExcludes(Set<String> privilegeExcludes) { public void setPrivilegeExcludes(Set<String> privilegeExcludes) {
this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes; this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes;
} }
/** /**
@@ -502,7 +517,7 @@ public final class ClassFilter<T> {
classes.add(classname); classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n"); if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) { for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname); if (filter != null) filter.filter(null, classname, url);
} }
} }
} }
@@ -511,7 +526,7 @@ public final class ClassFilter<T> {
} else { } else {
for (String classname : classes) { for (String classname : classes) {
for (final ClassFilter filter : filters) { for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname); if (filter != null) filter.filter(null, classname, url);
} }
} }
} }
@@ -530,14 +545,14 @@ public final class ClassFilter<T> {
classes.add(classname); classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n"); if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) { for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname); if (filter != null) filter.filter(null, classname, url);
} }
} }
cache.put(url, classes); cache.put(url, classes);
} else { } else {
for (String classname : classes) { for (String classname : classes) {
for (final ClassFilter filter : filters) { for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname); if (filter != null) filter.filter(null, classname, url);
} }
} }
} }

View File

@@ -9,6 +9,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level; import java.util.logging.Level;
import javax.annotation.*; import javax.annotation.*;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR; import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
@@ -217,6 +218,7 @@ public class NodeHttpServer extends NodeServer {
if (!rest) return; if (!rest) return;
if (restConf == null) return; //不存在REST服务 if (restConf == null) return; //不存在REST服务
final long starts = System.currentTimeMillis();
String prefix0 = restConf.getValue("path", ""); String prefix0 = restConf.getValue("path", "");
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1); if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0; if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
@@ -243,35 +245,45 @@ public class NodeHttpServer extends NodeServer {
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues); final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
final boolean finest = logger.isLoggable(Level.FINEST); final boolean finest = logger.isLoggable(Level.FINEST);
super.interceptorServices.forEach((service) -> { final CountDownLatch scdl = new CountDownLatch(super.interceptorServices.size());
final Class stype = Sncp.getServiceType(service); super.interceptorServices.stream().parallel().forEach((service) -> {
final String name = Sncp.getResourceName(service); try {
RestService rs = (RestService) stype.getAnnotation(RestService.class); final Class stype = Sncp.getServiceType(service);
if (rs == null || rs.ignore()) return; final String name = Sncp.getResourceName(service);
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs == null || rs.ignore()) return;
final String stypename = stype.getName(); final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return; if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return; if (!restFilter.accept(stypename)) return;
if (restedObjects.contains(service)) { synchronized (restedObjects) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore"); if (restedObjects.contains(service)) {
return; logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
} return;
restedObjects.add(service); //避免重复创建Rest对象 }
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix); restedObjects.add(service); //避免重复创建Rest对象
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
} }
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings)); HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
//if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
synchronized (ss) {
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName() + "(rest.name='" + name + "')", mappings));
}
}
} finally {
scdl.countDown();
} }
}); });
scdl.await();
} }
if (webSocketFilter != null) { //加载RestWebSocket if (webSocketFilter != null) { //加载RestWebSocket
final Set<String> includeValues = new HashSet<>(); final Set<String> includeValues = new HashSet<>();
@@ -340,6 +352,7 @@ public class NodeHttpServer extends NodeServer {
} }
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR); sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
} }
sb.append(threadName).append(" All HttpServlets load cost " + (System.currentTimeMillis() - starts) + " ms" + LINE_SEPARATOR);
} }
} }
} }

View File

@@ -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.*;
@@ -177,19 +178,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 +235,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 +298,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 +307,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
@@ -370,6 +389,7 @@ public abstract class NodeServer {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception { protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
if (serviceFilter == null) return; if (serviceFilter == null) return;
final long starts = System.currentTimeMillis();
final String threadName = "[" + Thread.currentThread().getName() + "] "; final String threadName = "[" + Thread.currentThread().getName() + "] ";
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys(); final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory; ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
@@ -401,6 +421,11 @@ public abstract class NodeServer {
if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类 if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> { final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try { try {
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的 通常为BaseService
logger.log(Level.FINE, serviceImplClass + " cannot load because not found less one public non-final method");
return;
}
Service service; Service service;
boolean ws = src instanceof WebSocketServlet; boolean ws = src instanceof WebSocketServlet;
if (ws || localed) { //本地模式 if (ws || localed) { //本地模式
@@ -408,8 +433,6 @@ public abstract class NodeServer {
} else { } else {
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty()); service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
} }
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) return; //class没有可用的方法且没有标记启动优先级的 通常为BaseService
final Class restype = Sncp.getResourceType(service); final Class restype = Sncp.getResourceType(service);
if (rf.find(resourceName, restype) == null) { if (rf.find(resourceName, restype) == null) {
regFactory.register(resourceName, restype, service); regFactory.register(resourceName, restype, service);
@@ -473,24 +496,19 @@ public abstract class NodeServer {
localServices.addAll(swlist); localServices.addAll(swlist);
//this.loadPersistData(); //this.loadPersistData();
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>(); final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
CountDownLatch clds = new CountDownLatch(localServices.size());
localServices.stream().forEach(y -> { localServices.stream().forEach(y -> {
try { long s = System.currentTimeMillis();
long s = System.currentTimeMillis(); y.init(Sncp.getConf(y));
y.init(Sncp.getConf(y)); long e = System.currentTimeMillis() - s;
long e = System.currentTimeMillis() - s; String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength); if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
} finally {
clds.countDown();
}
}); });
clds.await();
if (slist != null && sb != null) { if (slist != null && sb != null) {
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行) List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
for (String s : wlist) { for (String s : wlist) {
sb.append(s); sb.append(s);
} }
sb.append(threadName).append("All Services load cost " + (System.currentTimeMillis() - starts) + " ms" + LINE_SEPARATOR);
} }
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(Object.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 + ")");
} }
@@ -66,14 +66,15 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
} }
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 +85,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 +93,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 +109,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 +130,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;
} }
} }

View File

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

View File

@@ -45,6 +45,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
private final ConcurrentHashMap<String, Class> entitys = new ConcurrentHashMap(); private final ConcurrentHashMap<String, Class> entitys = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Map<String, SimpledCoder<R, W, ?>>> fieldCoders = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Decodeable<R, ?>> decoders = new ConcurrentHashMap(); private final ConcurrentHashMap<Type, Decodeable<R, ?>> decoders = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Encodeable<W, ?>> encoders = new ConcurrentHashMap(); private final ConcurrentHashMap<Type, Encodeable<W, ?>> encoders = new ConcurrentHashMap();
@@ -495,6 +497,29 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
encoders.put(clazz, encoder); encoders.put(clazz, encoder);
} }
//coder = null表示删除该字段的指定SimpledCoder
public final <E> void register(final Class clazz, final String field, final SimpledCoder<R, W, E> coder) {
if (field == null || clazz == null) return;
try {
clazz.getDeclaredField(field);
} catch (Exception e) {
throw new RuntimeException(clazz + " not found field(" + field + ")");
}
if (coder == null) {
Map map = this.fieldCoders.get(clazz);
if (map != null) map.remove(field);
} else {
this.fieldCoders.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>()).put(field, coder);
}
}
public final <E> SimpledCoder<R, W, E> findFieldCoder(final Type clazz, final String field) {
if (field == null) return null;
Map<String, SimpledCoder<R, W, ?>> map = this.fieldCoders.get(clazz);
if (map == null) return parent == null ? null : parent.findFieldCoder(clazz, field);
return (SimpledCoder) map.get(field);
}
public final <E> Decodeable<R, E> findDecoder(final Type type) { public final <E> Decodeable<R, E> findDecoder(final Type type) {
Decodeable<R, E> rs = (Decodeable<R, E>) decoders.get(type); Decodeable<R, E> rs = (Decodeable<R, E>) decoders.get(type);
if (rs != null) return rs; if (rs != null) return rs;

View File

@@ -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();
@@ -91,7 +91,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 +101,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 +131,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

View File

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

View File

@@ -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) {
@@ -93,8 +96,12 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
if (factory.isConvertDisabled(field)) continue; if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(field); ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t)); if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadDecoder(t);
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), fieldCoder);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }
@@ -118,8 +125,13 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
} }
ref = factory.findRef(method); ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t)); Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
fieldCoder = factory.loadDecoder(t);
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), fieldCoder);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }
@@ -220,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);
@@ -261,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]);

View File

@@ -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();
@@ -77,8 +77,12 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
if (factory.isConvertDisabled(field)) continue; if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(field); ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t)); if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t);
}
EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), fieldCoder);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }
@@ -102,8 +106,12 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
} }
ref = factory.findRef(method); ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type); Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t)); if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t);
}
EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), fieldCoder);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }

View File

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

View File

@@ -95,12 +95,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 +112,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);
/** /**
* 读取数组的尾端 * 读取数组的尾端

View File

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

View File

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

View File

@@ -130,12 +130,12 @@ public abstract class Writer {
* 输出一个数组前的操作 * 输出一个数组前的操作
* *
* @param size 数组长度 * @param size 数组长度
* @param encoder Encodeable * @param componentEncoder Encodeable
* @param obj 对象 * @param obj 对象
* *
* @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);
/** /**
* 输出数组元素间的间隔符 * 输出数组元素间的间隔符

View File

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

View File

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

View File

@@ -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) {

View File

@@ -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);
} }
/** /**
@@ -285,8 +247,11 @@ public class BsonWriter 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) {
writeInt(size); writeInt(size);
if (componentEncoder != null && componentEncoder != ByteSimpledCoder.instance) {
writeByte(BsonFactory.typeEnum(componentEncoder.getType()));
}
return -1; return -1;
} }
@@ -300,7 +265,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;
} }

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

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

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

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

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

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

View File

@@ -168,6 +168,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 +190,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 +209,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 +338,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 +479,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) {

View File

@@ -346,7 +346,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;
} }

View File

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

View File

@@ -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,
@@ -155,7 +156,7 @@ public class Context {
return bufferPool; return bufferPool;
} }
protected Consumer<ByteBuffer> getBufferConsumer() { public Consumer<ByteBuffer> getBufferConsumer() {
return bufferPool; return bufferPool;
} }
@@ -163,11 +164,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);

View File

@@ -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) {

View File

@@ -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) {

View File

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

View File

@@ -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; //输出的结果对象

View File

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

View File

@@ -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,19 +93,21 @@ 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(A attachment) {
@@ -223,13 +227,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

View File

@@ -33,7 +33,7 @@ public class TcpAioProtocolServer extends ProtocolServer {
@Override @Override
public void open(AnyValue config) throws IOException { public void open(AnyValue config) throws IOException {
//group = AsynchronousChannelGroup.withThreadPool(context.executor); //group = AsynchronousChannelGroup.withThreadPool(context.executor);
group = AsynchronousChannelGroup.withFixedThreadPool(context.executor.getCorePoolSize(), context.executor.getThreadFactory()); group = AsynchronousChannelGroup.withFixedThreadPool(context.executor.getCorePoolSize(), context.executor.getThreadFactory());
this.serverChannel = AsynchronousServerSocketChannel.open(group); this.serverChannel = AsynchronousServerSocketChannel.open(group);
final Set<SocketOption<?>> options = this.serverChannel.supportedOptions(); final Set<SocketOption<?>> options = this.serverChannel.supportedOptions();
@@ -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

View File

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

View File

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

View File

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

View File

@@ -29,41 +29,41 @@ import org.redkale.util.*;
* @author zhangjx * @author zhangjx
*/ */
public final class Transport { public final class Transport {
public static final String DEFAULT_PROTOCOL = "TCP"; public static final String DEFAULT_PROTOCOL = "TCP";
protected final AtomicInteger seq = new AtomicInteger(-1); protected final AtomicInteger seq = new AtomicInteger(-1);
protected final TransportFactory factory; protected final TransportFactory factory;
protected final String name; //即<group>的name属性 protected final String name; //即<group>的name属性
protected final String subprotocol; //即<group>的subprotocol属性 protected final String subprotocol; //即<group>的subprotocol属性
protected final boolean tcp; protected final boolean tcp;
protected final String protocol; protected final String protocol;
protected final AsynchronousChannelGroup group; protected final AsynchronousChannelGroup group;
protected final InetSocketAddress clientAddress; protected final InetSocketAddress clientAddress;
//不可能为null //不可能为null
protected TransportNode[] transportNodes = new TransportNode[0]; protected TransportNode[] transportNodes = new TransportNode[0];
protected final ObjectPool<ByteBuffer> bufferPool; protected final ObjectPool<ByteBuffer> bufferPool;
protected final SSLContext sslContext; protected final SSLContext sslContext;
//负载均衡策略 //负载均衡策略
protected final TransportStrategy strategy; protected final TransportStrategy strategy;
protected Transport(String name, String subprotocol, TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool, protected Transport(String name, String subprotocol, TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress, final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress,
final Collection<InetSocketAddress> addresses, final TransportStrategy strategy) { final Collection<InetSocketAddress> addresses, final TransportStrategy strategy) {
this(name, DEFAULT_PROTOCOL, subprotocol, factory, transportBufferPool, transportChannelGroup, sslContext, clientAddress, addresses, strategy); this(name, DEFAULT_PROTOCOL, subprotocol, factory, transportBufferPool, transportChannelGroup, sslContext, clientAddress, addresses, strategy);
} }
protected Transport(String name, String protocol, String subprotocol, protected Transport(String name, String protocol, String subprotocol,
final TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool, final TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress, final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress,
@@ -81,7 +81,7 @@ public final class Transport {
this.strategy = strategy; this.strategy = strategy;
updateRemoteAddresses(addresses); updateRemoteAddresses(addresses);
} }
public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) { public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) {
final TransportNode[] oldNodes = this.transportNodes; final TransportNode[] oldNodes = this.transportNodes;
synchronized (this) { synchronized (this) {
@@ -109,7 +109,7 @@ public final class Transport {
} }
return rs; return rs;
} }
public final boolean addRemoteAddresses(final InetSocketAddress addr) { public final boolean addRemoteAddresses(final InetSocketAddress addr) {
if (addr == null) return false; if (addr == null) return false;
if (clientAddress != null && clientAddress.equals(addr)) return false; if (clientAddress != null && clientAddress.equals(addr)) return false;
@@ -125,7 +125,7 @@ public final class Transport {
return true; return true;
} }
} }
public final boolean removeRemoteAddresses(InetSocketAddress addr) { public final boolean removeRemoteAddresses(InetSocketAddress addr) {
if (addr == null) return false; if (addr == null) return false;
synchronized (this) { synchronized (this) {
@@ -133,15 +133,15 @@ public final class Transport {
} }
return true; return true;
} }
public String getName() { public String getName() {
return name; return name;
} }
public String getSubprotocol() { public String getSubprotocol() {
return subprotocol; return subprotocol;
} }
public void close() { public void close() {
TransportNode[] nodes = this.transportNodes; TransportNode[] nodes = this.transportNodes;
if (nodes == null) return; if (nodes == null) return;
@@ -149,22 +149,22 @@ public final class Transport {
if (node != null) node.dispose(); if (node != null) node.dispose();
} }
} }
public InetSocketAddress getClientAddress() { public InetSocketAddress getClientAddress() {
return clientAddress; return clientAddress;
} }
public TransportNode[] getTransportNodes() { public TransportNode[] getTransportNodes() {
return transportNodes; return transportNodes;
} }
public TransportNode findTransportNode(SocketAddress addr) { public TransportNode findTransportNode(SocketAddress addr) {
for (TransportNode node : this.transportNodes) { for (TransportNode node : this.transportNodes) {
if (node.address.equals(addr)) return node; if (node.address.equals(addr)) return node;
} }
return null; return null;
} }
public InetSocketAddress[] getRemoteAddresses() { public InetSocketAddress[] getRemoteAddresses() {
InetSocketAddress[] rs = new InetSocketAddress[transportNodes.length]; InetSocketAddress[] rs = new InetSocketAddress[transportNodes.length];
for (int i = 0; i < rs.length; i++) { for (int i = 0; i < rs.length; i++) {
@@ -172,36 +172,36 @@ public final class Transport {
} }
return rs; return rs;
} }
@Override @Override
public String toString() { public String toString() {
return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteNodes = " + Arrays.toString(transportNodes) + "}"; return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteNodes = " + Arrays.toString(transportNodes) + "}";
} }
public ByteBuffer pollBuffer() { public ByteBuffer pollBuffer() {
return bufferPool.get(); return bufferPool.get();
} }
public Supplier<ByteBuffer> getBufferSupplier() { public Supplier<ByteBuffer> getBufferSupplier() {
return bufferPool; return bufferPool;
} }
public void offerBuffer(ByteBuffer buffer) { public void offerBuffer(ByteBuffer buffer) {
bufferPool.accept(buffer); bufferPool.accept(buffer);
} }
public void offerBuffer(ByteBuffer... buffers) { public void offerBuffer(ByteBuffer... buffers) {
for (ByteBuffer buffer : buffers) offerBuffer(buffer); for (ByteBuffer buffer : buffers) offerBuffer(buffer);
} }
public AsynchronousChannelGroup getTransportChannelGroup() { public AsynchronousChannelGroup getTransportChannelGroup() {
return group; return group;
} }
public boolean isTCP() { public boolean isTCP() {
return tcp; return tcp;
} }
public CompletableFuture<AsyncConnection> pollConnection(SocketAddress addr0) { public CompletableFuture<AsyncConnection> pollConnection(SocketAddress addr0) {
if (this.strategy != null) return strategy.pollConnection(addr0, this); if (this.strategy != null) return strategy.pollConnection(addr0, this);
final TransportNode[] nodes = this.transportNodes; final TransportNode[] nodes = this.transportNodes;
@@ -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,14 +266,14 @@ 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 {
future.complete(asyncConn); future.complete(asyncConn);
} }
} }
@Override @Override
public void failed(Throwable exc, TransportNode attachment) { public void failed(Throwable exc, TransportNode attachment) {
attachment.disabletime = now; attachment.disabletime = now;
@@ -289,7 +289,7 @@ public final class Transport {
future.complete(r); future.complete(r);
} }
}); });
} catch (Exception e) { } catch (Exception e) {
future.completeExceptionally(e); future.completeExceptionally(e);
} }
@@ -302,7 +302,7 @@ public final class Transport {
throw new RuntimeException("transport address = " + addr, ex); throw new RuntimeException("transport address = " + addr, ex);
} }
} }
private CompletableFuture<AsyncConnection> pollConnection0(TransportNode[] nodes, TransportNode exclude, long now) throws IOException { private CompletableFuture<AsyncConnection> pollConnection0(TransportNode[] nodes, TransportNode exclude, long now) throws IOException {
//从可用/不可用的地址列表中创建连接 //从可用/不可用的地址列表中创建连接
AtomicInteger count = new AtomicInteger(nodes.length); AtomicInteger count = new AtomicInteger(nodes.length);
@@ -319,17 +319,17 @@ 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 {
future.complete(asyncConn); future.complete(asyncConn);
} }
} catch (Exception e) { } catch (Exception e) {
failed(e, attachment); failed(e, attachment);
} }
} }
@Override @Override
public void failed(Throwable exc, TransportNode attachment) { public void failed(Throwable exc, TransportNode attachment) {
attachment.disabletime = now; attachment.disabletime = now;
@@ -345,7 +345,7 @@ public final class Transport {
} }
return future; return future;
} }
public void offerConnection(final boolean forceClose, AsyncConnection conn) { public void offerConnection(final boolean forceClose, AsyncConnection conn) {
if (this.strategy != null && strategy.offerConnection(forceClose, conn)) return; if (this.strategy != null && strategy.offerConnection(forceClose, conn)) return;
if (!forceClose && conn.isTCP()) { if (!forceClose && conn.isTCP()) {
@@ -359,7 +359,7 @@ public final class Transport {
conn.dispose(); conn.dispose();
} }
} }
public <A> void async(SocketAddress addr, final ByteBuffer buffer, A att, final CompletionHandler<Integer, A> handler) { public <A> void async(SocketAddress addr, final ByteBuffer buffer, A att, final CompletionHandler<Integer, A> handler) {
pollConnection(addr).whenComplete((conn, ex) -> { pollConnection(addr).whenComplete((conn, ex) -> {
if (ex != null) { if (ex != null) {
@@ -367,118 +367,119 @@ public final class Transport {
return; return;
} }
conn.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() { conn.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@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);
} }
}); });
} }
@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);
} }
}); });
}); });
} }
public static class TransportNode { public static class TransportNode {
protected InetSocketAddress address; protected InetSocketAddress address;
protected volatile long disabletime; //不可用时的时间, 为0表示可用 protected volatile long disabletime; //不可用时的时间, 为0表示可用
protected final BlockingQueue<AsyncConnection> conns; protected final BlockingQueue<AsyncConnection> conns;
protected final ConcurrentHashMap<String, Object> attributes = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, Object> attributes = new ConcurrentHashMap<>();
public TransportNode(int poolmaxconns, InetSocketAddress address) { public TransportNode(int poolmaxconns, InetSocketAddress address) {
this.address = address; this.address = address;
this.disabletime = 0; this.disabletime = 0;
this.conns = new ArrayBlockingQueue<>(poolmaxconns); this.conns = new ArrayBlockingQueue<>(poolmaxconns);
} }
@ConstructorParameters({"poolmaxconns", "address", "disabletime"}) @ConstructorParameters({"poolmaxconns", "address", "disabletime"})
public TransportNode(int poolmaxconns, InetSocketAddress address, long disabletime) { public TransportNode(int poolmaxconns, InetSocketAddress address, long disabletime) {
this.address = address; this.address = address;
this.disabletime = disabletime; this.disabletime = disabletime;
this.conns = new LinkedBlockingQueue<>(poolmaxconns); this.conns = new LinkedBlockingQueue<>(poolmaxconns);
} }
public int getPoolmaxconns() { public int getPoolmaxconns() {
return this.conns.remainingCapacity() + this.conns.size(); return this.conns.remainingCapacity() + this.conns.size();
} }
public <T> T setAttribute(String name, T value) { public <T> T setAttribute(String name, T value) {
attributes.put(name, value); attributes.put(name, value);
return value; return value;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T getAttribute(String name) { public <T> T getAttribute(String name) {
return (T) attributes.get(name); return (T) attributes.get(name);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T removeAttribute(String name) { public <T> T removeAttribute(String name) {
return (T) attributes.remove(name); return (T) attributes.remove(name);
} }
public TransportNode clearAttributes() { public TransportNode clearAttributes() {
attributes.clear(); attributes.clear();
return this; return this;
} }
public ConcurrentHashMap<String, Object> getAttributes() { public ConcurrentHashMap<String, Object> getAttributes() {
return attributes; return attributes;
} }
public void setAttributes(ConcurrentHashMap<String, Object> map) { public void setAttributes(ConcurrentHashMap<String, Object> map) {
attributes.clear(); attributes.clear();
if (map != null) attributes.putAll(map); if (map != null) attributes.putAll(map);
} }
public InetSocketAddress getAddress() { public InetSocketAddress getAddress() {
return address; return address;
} }
public long getDisabletime() { public long getDisabletime() {
return disabletime; return disabletime;
} }
@ConvertDisabled @ConvertDisabled
public BlockingQueue<AsyncConnection> getConns() { public BlockingQueue<AsyncConnection> getConns() {
return conns; return conns;
} }
public void dispose() { public void dispose() {
AsyncConnection conn; AsyncConnection conn;
while ((conn = conns.poll()) != null) { while ((conn = conns.poll()) != null) {
conn.dispose(); conn.dispose();
} }
} }
@Override @Override
public int hashCode() { public int hashCode() {
return this.address.hashCode(); return this.address.hashCode();
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) return true; if (this == obj) return true;
@@ -487,7 +488,7 @@ public final class Transport {
final TransportNode other = (TransportNode) obj; final TransportNode other = (TransportNode) obj;
return this.address.equals(other.address); return this.address.equals(other.address);
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -126,7 +126,8 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
List<HttpServlet> list = removeHttpServlet(predicateEntry, predicateFilter); List<HttpServlet> list = removeHttpServlet(predicateEntry, predicateFilter);
return list == null || list.isEmpty() ? null : list.get(0); return list == null || list.isEmpty() ? null : list.get(0);
} }
@SuppressWarnings("unchecked")
@SuppressWarnings("unchecked")
public <T extends WebSocket> HttpServlet removeHttpServlet(Class<T> websocketOrServletType) { public <T extends WebSocket> HttpServlet removeHttpServlet(Class<T> websocketOrServletType) {
Predicate<MappingEntry> predicateEntry = (t) -> { Predicate<MappingEntry> predicateEntry = (t) -> {
Class type = t.servlet.getClass(); Class type = t.servlet.getClass();
@@ -151,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 {
@@ -310,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);
} }
} }

View File

@@ -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) {
@@ -614,15 +614,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
@Override @Override
public void finish(final byte[] bs) { public void finish(final byte[] bs) {
if (isClosed()) return; //避免重复关闭 this.finish(this.contentType, bs);
if (this.context.getBufferCapacity() >= bs.length) {
ByteBuffer buffer = getBodyBufferSupplier().get();
buffer.put(bs);
buffer.flip();
this.finish(false, buffer);
} else {
this.finish(false, ByteBuffer.wrap(bs));
}
} }
/** /**
@@ -633,15 +625,30 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finish(final String contentType, final byte[] bs) { public void finish(final String contentType, final byte[] bs) {
if (isClosed()) return; //避免重复关闭 if (isClosed()) return; //避免重复关闭
this.contentType = contentType; final byte[] content = bs == null ? new byte[0] : bs;
if (this.context.getBufferCapacity() >= bs.length) { if (!this.headsended) {
ByteBuffer buffer = getBodyBufferSupplier().get(); this.contentType = contentType;
buffer.put(bs); this.contentLength = content.length;
buffer.flip(); ByteBuffer headbuf = createHeader();
this.finish(false, buffer); if (headbuf.remaining() >= content.length) {
headbuf.put(content);
headbuf.flip();
super.finish(false, headbuf);
} else {
headbuf.flip();
super.finish(false, new ByteBuffer[]{headbuf, ByteBuffer.wrap(content)});
}
} else { } else {
this.finish(false, ByteBuffer.wrap(bs)); if (this.context.getBufferCapacity() >= content.length) {
ByteBuffer buffer = getBodyBufferSupplier().get();
buffer.put(content);
buffer.flip();
this.finish(false, buffer);
} else {
this.finish(false, ByteBuffer.wrap(content));
}
} }
} }
/** /**
@@ -887,16 +894,21 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
buffer.put(("HTTP/1.1 " + this.status + " " + httpCodes.get(this.status) + "\r\n").getBytes()); buffer.put(("HTTP/1.1 " + this.status + " " + httpCodes.get(this.status) + "\r\n").getBytes());
} }
if (this.contentLength >= 0) buffer.put(("Content-Length: " + this.contentLength + "\r\n").getBytes()); if (this.contentLength >= 0) buffer.put(("Content-Length: " + this.contentLength + "\r\n").getBytes());
if (this.contentType == this.jsonContentType) { if (!this.request.isWebSocket()) {
buffer.put(this.jsonContentTypeBytes); if (this.contentType == this.jsonContentType) {
} else if (this.contentType == null || this.contentType == this.plainContentType) { buffer.put(this.jsonContentTypeBytes);
buffer.put(this.plainContentTypeBytes); } else if (this.contentType == null || this.contentType == this.plainContentType) {
} else { buffer.put(this.plainContentTypeBytes);
buffer.put(("Content-Type: " + (this.contentType == null ? this.plainContentType : this.contentType) + "\r\n").getBytes()); } else {
buffer.put(("Content-Type: " + (this.contentType == null ? this.plainContentType : this.contentType) + "\r\n").getBytes());
}
} }
buffer.put(serverNameBytes); buffer.put(serverNameBytes);
if (dateSupplier != null) buffer.put(dateSupplier.get()); if (dateSupplier != null) buffer.put(dateSupplier.get());
buffer.put(this.request.isKeepAlive() ? connectAliveBytes : connectCloseBytes);
if (this.header.getValue("Connection") == null) {
buffer.put(this.request.isKeepAlive() ? connectAliveBytes : connectCloseBytes);
}
if (this.defaultAddHeaders != null) { if (this.defaultAddHeaders != null) {
for (String[] headers : this.defaultAddHeaders) { for (String[] headers : this.defaultAddHeaders) {

View File

@@ -256,17 +256,19 @@ public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpRes
final boolean sncp = Sncp.isSncpDyn(service); final boolean sncp = Sncp.isSncpDyn(service);
final String resname = name == null ? (sncp ? Sncp.getResourceName(service) : "") : name; final String resname = name == null ? (sncp ? Sncp.getResourceName(service) : "") : name;
final Class<S> serviceType = Sncp.getServiceType(service); final Class<S> serviceType = Sncp.getServiceType(service);
for (final HttpServlet item : ((HttpPrepareServlet) this.prepare).getServlets()) { if (name != null) {
if (!(item instanceof HttpServlet)) continue; for (final HttpServlet item : ((HttpPrepareServlet) this.prepare).getServlets()) {
if (item.getClass().getAnnotation(Rest.RestDyn.class) == null) continue; if (!(item instanceof HttpServlet)) continue;
try { if (item.getClass().getAnnotation(Rest.RestDyn.class) == null) continue;
Field field = item.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME); try {
if (serviceType.equals(field.getType())) { Field field = item.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
servlet = (T) item; if (serviceType.equals(field.getType())) {
break; servlet = (T) item;
break;
}
} catch (NoSuchFieldException | SecurityException e) {
logger.log(Level.SEVERE, "serviceType = " + serviceType + ", servletClass = " + item.getClass(), e);
} }
} catch (NoSuchFieldException | SecurityException e) {
logger.log(Level.SEVERE, "serviceType = " + serviceType + ", servletClass = " + item.getClass(), e);
} }
} }
final boolean first = servlet == null; final boolean first = servlet == null;

View File

@@ -34,13 +34,15 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
String _prefix = ""; //当前HttpServlet的path前缀 String _prefix = ""; //当前HttpServlet的path前缀
private Map.Entry<String, Entry>[] mappings; HashMap<String, InnerActionEntry> _tmpentrys; //Rest生成时赋值, 字段名Rest有用到
private Map.Entry<String, InnerActionEntry>[] mappings; //字段名Rest有用到
//这里不能直接使用HttpServlet会造成死循环初始化HttpServlet //这里不能直接使用HttpServlet会造成死循环初始化HttpServlet
private final Servlet<HttpContext, HttpRequest, HttpResponse> authSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() { private final Servlet<HttpContext, HttpRequest, HttpResponse> authSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() {
@Override @Override
public void execute(HttpRequest request, HttpResponse response) throws IOException { public void execute(HttpRequest request, HttpResponse response) throws IOException {
Entry entry = (Entry) request.attachment; InnerActionEntry entry = (InnerActionEntry) request.attachment;
if (entry.cacheseconds > 0) {//有缓存设置 if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI()); CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效 if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
@@ -59,9 +61,9 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
private final Servlet<HttpContext, HttpRequest, HttpResponse> preSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() { private final Servlet<HttpContext, HttpRequest, HttpResponse> preSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() {
@Override @Override
public void execute(HttpRequest request, HttpResponse response) throws IOException { public void execute(HttpRequest request, HttpResponse response) throws IOException {
for (Map.Entry<String, Entry> en : mappings) { for (Map.Entry<String, InnerActionEntry> en : mappings) {
if (request.getRequestURI().startsWith(en.getKey())) { if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue(); InnerActionEntry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) { if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error")); response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return; return;
@@ -69,11 +71,11 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
request.attachment = entry; request.attachment = entry;
request.moduleid = entry.moduleid; request.moduleid = entry.moduleid;
request.actionid = entry.actionid; request.actionid = entry.actionid;
if (entry.ignore) { if (entry.auth) {
authSuccessServlet.execute(request, response);
} else {
response.thenEvent(authSuccessServlet); response.thenEvent(authSuccessServlet);
authenticate(request, response); authenticate(request, response);
} else {
authSuccessServlet.execute(request, response);
} }
return; return;
} }
@@ -84,13 +86,14 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
void preInit(HttpContext context, AnyValue config) { void preInit(HttpContext context, AnyValue config) {
if (this.mappings != null) return; //无需重复preInit
String path = _prefix == null ? "" : _prefix; String path = _prefix == null ? "" : _prefix;
WebServlet ws = this.getClass().getAnnotation(WebServlet.class); WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = ""; if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load(); HashMap<String, InnerActionEntry> map = this._tmpentrys != null ? this._tmpentrys : loadActionEntry();
this.mappings = new Map.Entry[map.size()]; this.mappings = new Map.Entry[map.size()];
int i = -1; int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) { for (Map.Entry<String, InnerActionEntry> en : map.entrySet()) {
mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue()); mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
} }
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query //必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
@@ -163,10 +166,10 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
preExecute(request, response); preExecute(request, response);
} }
private HashMap<String, Entry> load() { private HashMap<String, InnerActionEntry> loadActionEntry() {
WebServlet module = this.getClass().getAnnotation(WebServlet.class); WebServlet module = this.getClass().getAnnotation(WebServlet.class);
final int serviceid = module == null ? 0 : module.moduleid(); final int serviceid = module == null ? 0 : module.moduleid();
final HashMap<String, Entry> map = new HashMap<>(); final HashMap<String, InnerActionEntry> map = new HashMap<>();
HashMap<String, Class> nameset = new HashMap<>(); HashMap<String, Class> nameset = new HashMap<>();
final Class selfClz = this.getClass(); final Class selfClz = this.getClass();
Class clz = this.getClass(); Class clz = this.getClass();
@@ -197,13 +200,82 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + HttpMapping.class.getSimpleName() + "(" + name + ")"); throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + HttpMapping.class.getSimpleName() + "(" + name + ")");
} }
nameset.put(name, clz); nameset.put(name, clz);
map.put(name, new Entry(serviceid, actionid, name, methods, method, createHttpServlet(method))); map.put(name, new InnerActionEntry(serviceid, actionid, name, methods, method, createActionServlet(method)));
} }
} while ((clz = clz.getSuperclass()) != HttpServlet.class); } while ((clz = clz.getSuperclass()) != HttpServlet.class);
return map; return map;
} }
private HttpServlet createHttpServlet(final Method method) { protected static final class InnerActionEntry {
InnerActionEntry(int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) {
this(moduleid, actionid, name, methods, method, auth(method), cacheseconds(method), servlet);
}
//供Rest类使用参数不能随便更改
public InnerActionEntry(int moduleid, int actionid, String name, String[] methods, Method method, boolean auth, int cacheseconds, HttpServlet servlet) {
this.moduleid = moduleid;
this.actionid = actionid;
this.name = name;
this.methods = methods;
this.method = method; //rest构建会为null
this.servlet = servlet;
this.auth = auth;
this.cacheseconds = cacheseconds;
this.cache = cacheseconds > 0 ? new ConcurrentHashMap<>() : null;
this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus();
if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
cache.put(response.getRequest().getRequestURI(), ce);
return ce.getBuffers();
} : null;
}
private static boolean auth(Method method) {
HttpMapping mapping = method.getAnnotation(HttpMapping.class);
return mapping == null || mapping.auth();
}
private static int cacheseconds(Method method) {
HttpMapping mapping = method.getAnnotation(HttpMapping.class);
return mapping == null ? 0 : mapping.cacheseconds();
}
boolean isNeedCheck() {
return this.moduleid != 0 || this.actionid != 0;
}
boolean checkMethod(final String reqMethod) {
if (methods.length == 0) return true;
for (String m : methods) {
if (reqMethod.equalsIgnoreCase(m)) return true;
}
return false;
}
final BiFunction<HttpResponse, ByteBuffer[], ByteBuffer[]> cacheHandler;
final ConcurrentHashMap<String, CacheEntry> cache;
final int cacheseconds;
final boolean auth;
final int moduleid;
final int actionid;
final String name;
final String[] methods;
final Method method;
final HttpServlet servlet;
}
private HttpServlet createActionServlet(final Method method) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
final String supDynName = HttpServlet.class.getName().replace('.', '/'); final String supDynName = HttpServlet.class.getName().replace('.', '/');
final String interName = this.getClass().getName().replace('.', '/'); final String interName = this.getClass().getName().replace('.', '/');
@@ -282,61 +354,6 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
} }
} }
private static final class Entry {
public Entry(int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) {
this.moduleid = moduleid;
this.actionid = actionid;
this.name = name;
this.methods = methods;
this.method = method;
this.servlet = servlet;
HttpMapping mapping = method.getAnnotation(HttpMapping.class);
this.ignore = mapping == null || !mapping.auth();
this.cacheseconds = mapping == null ? 0 : mapping.cacheseconds();
this.cache = cacheseconds > 0 ? new ConcurrentHashMap<>() : null;
this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus();
if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
cache.put(response.getRequest().getRequestURI(), ce);
return ce.getBuffers();
} : null;
}
public boolean isNeedCheck() {
return this.moduleid != 0 || this.actionid != 0;
}
public boolean checkMethod(final String reqMethod) {
if (methods.length == 0) return true;
for (String m : methods) {
if (reqMethod.equalsIgnoreCase(m)) return true;
}
return false;
}
public final BiFunction<HttpResponse, ByteBuffer[], ByteBuffer[]> cacheHandler;
public final ConcurrentHashMap<String, CacheEntry> cache;
public final int cacheseconds;
public final boolean ignore;
public final int moduleid;
public final int actionid;
public final String name;
public final String[] methods;
public final Method method;
public final HttpServlet servlet;
}
private static final class CacheEntry { private static final class CacheEntry {
public final long time = System.currentTimeMillis(); public final long time = System.currentTimeMillis();

View File

@@ -12,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 配合 HttpServlet 使用。 * 配合 HttpServlet 使用。
* 用于指定HttpRequest.currentUser的数据类型。<br> * 用于指定HttpRequest.currentUser的数据类型。<br>
* 注意: 数据类型是JavaBean则必须要用javax.persistence.Id标记主键字段用于确定用户ID * 注意: 数据类型是JavaBean
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -39,6 +39,8 @@ public final class Rest {
static final String REST_SERVICE_FIELD_NAME = "_redkale_service"; static final String REST_SERVICE_FIELD_NAME = "_redkale_service";
static final String REST_TOSTRINGOBJ_FIELD_NAME = "_redkale_tostringsupplier";
static final String REST_JSONCONVERT_FIELD_PREFIX = "_redkale_jsonconvert_"; static final String REST_JSONCONVERT_FIELD_PREFIX = "_redkale_jsonconvert_";
static final String REST_SERVICEMAP_FIELD_NAME = "_redkale_servicemap"; //如果只有name=""的Service资源则实例中_servicemap必须为null static final String REST_SERVICEMAP_FIELD_NAME = "_redkale_servicemap"; //如果只有name=""的Service资源则实例中_servicemap必须为null
@@ -127,25 +129,37 @@ public final class Rest {
} }
} }
static JsonConvert createJsonConvert(RestConvert[] converts) { static JsonConvert createJsonConvert(RestConvert[] converts, RestConvertCoder[] coders) {
if (converts == null || converts.length < 1) return JsonConvert.root(); if ((converts == null || converts.length < 1) && (coders == null || coders.length < 1)) return JsonConvert.root();
final JsonFactory childFactory = JsonFactory.create(); final JsonFactory childFactory = JsonFactory.create();
List<Class> types = new ArrayList<>(); List<Class> types = new ArrayList<>();
for (RestConvert rc : converts) { Set<Class> reloadTypes = new HashSet<>();
if (rc.type() == void.class || rc.type() == Void.class) { if (coders != null) {
return JsonFactory.create().skipAllIgnore(true).getConvert(); for (RestConvertCoder rcc : coders) {
reloadTypes.add(rcc.type());
childFactory.register(rcc.type(), rcc.field(), Creator.create(rcc.coder()).create());
} }
if (types.contains(rc.type())) throw new RuntimeException("@RestConvert type(" + rc.type() + ") repeat"); }
if (rc.skipIgnore()) { if (converts != null) {
childFactory.registerSkipIgnore(rc.type()); for (RestConvert rc : converts) {
childFactory.reloadCoder(rc.type()); if (rc.type() == void.class || rc.type() == Void.class) {
} else { return JsonFactory.create().skipAllIgnore(true).getConvert();
childFactory.register(rc.type(), false, rc.convertColumns()); }
childFactory.register(rc.type(), true, rc.ignoreColumns()); if (types.contains(rc.type())) throw new RuntimeException("@RestConvert type(" + rc.type() + ") repeat");
childFactory.reloadCoder(rc.type()); if (rc.skipIgnore()) {
childFactory.registerSkipIgnore(rc.type());
childFactory.reloadCoder(rc.type());
} else {
childFactory.register(rc.type(), false, rc.convertColumns());
childFactory.register(rc.type(), true, rc.ignoreColumns());
childFactory.reloadCoder(rc.type());
}
types.add(rc.type());
childFactory.tiny(rc.tiny());
} }
types.add(rc.type()); }
childFactory.tiny(rc.tiny()); for (Class type : reloadTypes) {
childFactory.reloadCoder(type);
} }
return childFactory.getConvert(); return childFactory.getConvert();
} }
@@ -239,7 +253,19 @@ public final class Rest {
final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString(); final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString();
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), webSocketType); boolean namePresent = false;
try {
Method m0 = null;
for (Method method : webSocketType.getMethods()) {
if (method.getParameterCount() > 0) {
m0 = method;
break;
}
}
namePresent = m0 == null ? true : m0.getParameters()[0].isNamePresent();
} catch (Exception e) {
}
final Map<String, List<String>> asmParamMap = namePresent ? null : MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), webSocketType);
final Set<String> messageNames = new HashSet<>(); final Set<String> messageNames = new HashSet<>();
final List<Method> messageMethods = new ArrayList<>(); final List<Method> messageMethods = new ArrayList<>();
for (Method method : webSocketType.getMethods()) { for (Method method : webSocketType.getMethods()) {
@@ -402,7 +428,7 @@ public final class Rest {
cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
Set<String> paramnames = new HashSet<>(); Set<String> paramnames = new HashSet<>();
String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method); String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method);
List<String> names = asmParamMap.get(methodesc); List<String> names = asmParamMap == null ? null : asmParamMap.get(methodesc);
if (names != null) while (names.remove(" ")); //删掉空元素 if (names != null) while (names.remove(" ")); //删掉空元素
Parameter[] params = method.getParameters(); Parameter[] params = method.getParameters();
final LinkedHashMap<String, Parameter> paramap = new LinkedHashMap(); //必须使用LinkedHashMap确保顺序 final LinkedHashMap<String, Parameter> paramap = new LinkedHashMap(); //必须使用LinkedHashMap确保顺序
@@ -676,7 +702,8 @@ public final class Rest {
final String retDesc = Type.getDescriptor(RetResult.class); final String retDesc = Type.getDescriptor(RetResult.class);
final String futureDesc = Type.getDescriptor(CompletableFuture.class); final String futureDesc = Type.getDescriptor(CompletableFuture.class);
final String flipperDesc = Type.getDescriptor(Flipper.class); final String flipperDesc = Type.getDescriptor(Flipper.class);
final String httprsDesc = Type.getDescriptor(HttpResult.class); final String httpServletName = HttpServlet.class.getName().replace('.', '/');
final String innerEntryName = HttpServlet.InnerActionEntry.class.getName().replace('.', '/');
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class); final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
final String multiContextDesc = Type.getDescriptor(MultiContext.class); final String multiContextDesc = Type.getDescriptor(MultiContext.class);
final String multiContextName = MultiContext.class.getName().replace('.', '/'); final String multiContextName = MultiContext.class.getName().replace('.', '/');
@@ -693,12 +720,21 @@ public final class Rest {
HttpUserType hut = baseServletType.getAnnotation(HttpUserType.class); HttpUserType hut = baseServletType.getAnnotation(HttpUserType.class);
final Class userType = (userType0 == null || userType0 == Object.class) ? (hut == null ? null : hut.value()) : userType0; final Class userType = (userType0 == null || userType0 == Object.class) ? (hut == null ? null : hut.value()) : userType0;
if (userType != null && (userType.isPrimitive() || userType.getName().startsWith("java.") || userType.getName().startsWith("javax."))) {
throw new RuntimeException(HttpUserType.class.getSimpleName() + " must be a JavaBean but found " + userType);
}
final String supDynName = baseServletType.getName().replace('.', '/'); final String supDynName = baseServletType.getName().replace('.', '/');
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);
@@ -750,13 +786,12 @@ public final class Rest {
if (ignore) continue; if (ignore) continue;
Class[] extypes = method.getExceptionTypes(); Class[] extypes = method.getExceptionTypes();
if (extypes.length > 1) { if (extypes.length > 0) {
if (mappings != null && mappings.length > 0) throw new RuntimeException("@" + RestMapping.class.getSimpleName() + " only for method with throws IOException"); for (Class exp : extypes) {
continue; if (!RuntimeException.class.isAssignableFrom(exp) && !IOException.class.isAssignableFrom(exp)) {
} throw new RuntimeException("@" + RestMapping.class.getSimpleName() + " only for method(" + method + ") with throws IOException");
if (extypes.length == 1 && extypes[0] != IOException.class) { }
if (mappings != null && mappings.length > 0) throw new RuntimeException("@" + RestMapping.class.getSimpleName() + " only for method with throws IOException"); }
continue;
} }
paramtypes.add(TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType)); paramtypes.add(TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType));
if (mappings.length == 0) { //没有Mapping设置一个默认值 if (mappings.length == 0) { //没有Mapping设置一个默认值
@@ -774,9 +809,10 @@ public final class Rest {
} }
if (entrys.isEmpty()) return null; //没有可HttpMapping的方法 if (entrys.isEmpty()) return null; //没有可HttpMapping的方法
RestClassLoader newLoader = new RestClassLoader(loader);
final int moduleid = controller == null ? 0 : controller.moduleid();
{ //注入 @WebServlet 注解 { //注入 @WebServlet 注解
String urlpath = ""; String urlpath = "";
int moduleid = controller == null ? 0 : controller.moduleid();
boolean repair = controller == null ? true : controller.repair(); boolean repair = controller == null ? true : controller.repair();
String comment = controller == null ? "" : controller.comment(); String comment = controller == null ? "" : controller.comment();
av0 = cw.visitAnnotation(webServletDesc, true); av0 = cw.visitAnnotation(webServletDesc, true);
@@ -812,7 +848,13 @@ public final class Rest {
classMap.put("repair", repair); classMap.put("repair", repair);
//classMap.put("comment", comment); //不显示太多信息 //classMap.put("comment", comment); //不显示太多信息
} }
{ //内部类
cw.visitInnerClass(innerEntryName, httpServletName, HttpServlet.InnerActionEntry.class.getSimpleName(), ACC_PROTECTED + ACC_FINAL + ACC_STATIC);
for (final MappingEntry entry : entrys) {
cw.visitInnerClass(newDynName + "$" + entry.newActionClassName, newDynName, entry.newActionClassName, ACC_PRIVATE + ACC_STATIC);
}
}
{ //注入 @Resource private XXXService _service; { //注入 @Resource private XXXService _service;
fv = cw.visitField(ACC_PRIVATE, REST_SERVICE_FIELD_NAME, serviceDesc, null, null); fv = cw.visitField(ACC_PRIVATE, REST_SERVICE_FIELD_NAME, serviceDesc, null, null);
av0 = fv.visitAnnotation(resDesc, true); av0 = fv.visitAnnotation(resDesc, true);
@@ -835,6 +877,10 @@ public final class Rest {
fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null); fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null);
fv.visitEnd(); fv.visitEnd();
} }
{ //_redkale_tostringsupplier字段 Supplier<String>
fv = cw.visitField(ACC_PRIVATE, REST_TOSTRINGOBJ_FIELD_NAME, "Ljava/util/function/Supplier;", "Ljava/util/function/Supplier<Ljava/lang/String;>;", null);
fv.visitEnd();
}
{ //构造函数 { //构造函数
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)); mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true); //mv.setDebug(true);
@@ -846,10 +892,22 @@ public final class Rest {
} }
//将每个Service可转换的方法生成HttpServlet对应的HttpMapping方法 //将每个Service可转换的方法生成HttpServlet对应的HttpMapping方法
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), serviceType); boolean namePresent = false;
try {
Method m0 = null;
for (final MappingEntry entry : entrys) {
if (entry.mappingMethod.getParameterCount() > 0) {
m0 = entry.mappingMethod;
break;
}
}
namePresent = m0 == null ? true : m0.getParameters()[0].isNamePresent();
} catch (Exception e) {
}
final Map<String, List<String>> asmParamMap = namePresent ? null : MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), serviceType);
final Map<String, java.lang.reflect.Type> bodyTypes = new HashMap<>(); final Map<String, java.lang.reflect.Type> bodyTypes = new HashMap<>();
final List<RestConvert[]> restConverts = new ArrayList<>(); final List<Object[]> restConverts = new ArrayList<>();
for (final MappingEntry entry : entrys) { for (final MappingEntry entry : entrys) {
RestUploadFile mupload = null; RestUploadFile mupload = null;
Class muploadType = null; Class muploadType = null;
@@ -859,9 +917,12 @@ public final class Rest {
final Parameter[] params = method.getParameters(); final Parameter[] params = method.getParameters();
final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class); final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class);
if (rcs != null && rcs.length > 0) restConverts.add(rcs); final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class);
if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) {
restConverts.add(new Object[]{rcs, rcc});
}
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, entry.name.replace('/', '$').replace('.', '_'), "(" + reqDesc + respDesc + ")V", null, new String[]{"java/io/IOException"})); mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, entry.newMethodName, "(" + reqDesc + respDesc + ")V", null, new String[]{"java/io/IOException"}));
//mv.setDebug(true); //mv.setDebug(true);
mv.debugLine(); mv.debugLine();
@@ -1042,6 +1103,7 @@ public final class Rest {
mappingMap.put("comment", entry.comment); mappingMap.put("comment", entry.comment);
mappingMap.put("methods", entry.methods); mappingMap.put("methods", entry.methods);
mappingMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt)); mappingMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
entry.mappingurl = url;
} }
{ // 设置 Annotation { // 设置 Annotation
@@ -1695,8 +1757,99 @@ public final class Rest {
mv.visitMaxs(maxStack, maxLocals); mv.visitMaxs(maxStack, maxLocals);
mappingMap.put("params", paramMaps); mappingMap.put("params", paramMaps);
mappingMaps.add(mappingMap); mappingMaps.add(mappingMap);
{ //_Dync_XXX__HttpServlet.class
ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
cw2.visit(V1_8, ACC_SUPER, newDynName + "$" + entry.newActionClassName, null, httpServletName, null);
cw2.visitInnerClass(newDynName + "$" + entry.newActionClassName, newDynName, entry.newActionClassName, ACC_PRIVATE + ACC_STATIC);
{
fv = cw2.visitField(0, "servlet", "L" + newDynName + ";", null, null);
fv.visitEnd();
}
{
mv = new MethodDebugVisitor(cw2.visitMethod(0, "<init>", "(L" + newDynName + ";)V", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, httpServletName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName + "$" + entry.newActionClassName, "servlet", "L" + newDynName + ";");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
if (false) {
mv = new MethodDebugVisitor(cw2.visitMethod(ACC_SYNTHETIC, "<init>", "(L" + newDynName + ";L" + newDynName + "$" + entry.newActionClassName + ";)V", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, newDynName + "$" + entry.newActionClassName, "<init>", "L" + newDynName + ";", false);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 3);
mv.visitEnd();
}
{
mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "execute", "(" + reqDesc + respDesc + ")V", null, new String[]{"java/io/IOException"}));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName + "$" + entry.newActionClassName, "servlet", "L" + newDynName + ";");
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, entry.newMethodName, "(" + reqDesc + respDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
cw2.visitEnd();
newLoader.addClass((newDynName + "$" + entry.newActionClassName).replace('/', '.'), cw2.toByteArray());
}
} // end for each } // end for each
// HashMap<String, InnerActionEntry> _createRestInnerActionEntry() {
// HashMap<String, InnerActionEntry> map = new HashMap<>();
// map.put("asyncfind3", new InnerActionEntry(100000,200000,"asyncfind3", new String[]{},null,false,0, new _Dync_asyncfind3_HttpServlet()));
// map.put("asyncfind3", new InnerActionEntry(1,2,"asyncfind2", new String[]{"GET", "POST"},null,true,0, new _Dync_asyncfind2_HttpServlet()));
// return map;
// }
{ //_createRestInnerActionEntry 方法
mv = new MethodDebugVisitor(cw.visitMethod(0, "_createRestInnerActionEntry", "()Ljava/util/HashMap;", "()Ljava/util/HashMap<Ljava/lang/String;L" + innerEntryName + ";>;", null));
//mv.setDebug(true);
mv.visitTypeInsn(NEW, "java/util/HashMap");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V", false);
mv.visitVarInsn(ASTORE, 1);
for (final MappingEntry entry : entrys) {
mv.visitVarInsn(ALOAD, 1);
mv.visitLdcInsn(entry.mappingurl); //name
mv.visitTypeInsn(NEW, innerEntryName); //new InnerActionEntry
mv.visitInsn(DUP);
pushInt(mv, moduleid); //moduleid
pushInt(mv, entry.actionid); //actionid
mv.visitLdcInsn(entry.mappingurl); //name
pushInt(mv, entry.methods.length); //methods
mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
for (int i = 0; i < entry.methods.length; i++) {
mv.visitInsn(DUP);
pushInt(mv, i);
mv.visitLdcInsn(entry.methods[i]);
mv.visitInsn(AASTORE);
}
mv.visitInsn(ACONST_NULL); //method
mv.visitInsn(entry.auth ? ICONST_1 : ICONST_0); //auth
pushInt(mv, entry.cacheseconds); //cacheseconds
mv.visitTypeInsn(NEW, newDynName + "$" + entry.newActionClassName);
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, newDynName + "$" + entry.newActionClassName, "<init>", "(L" + newDynName + ";)V", false);
mv.visitMethodInsn(INVOKESPECIAL, innerEntryName, "<init>", "(IILjava/lang/String;[Ljava/lang/String;Ljava/lang/reflect/Method;ZILorg/redkale/net/http/HttpServlet;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(POP);
}
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
for (Map.Entry<String, java.lang.reflect.Type> en : bodyTypes.entrySet()) { for (Map.Entry<String, java.lang.reflect.Type> en : bodyTypes.entrySet()) {
fv = cw.visitField(ACC_PRIVATE, en.getKey(), "Ljava/lang/reflect/Type;", null, null); fv = cw.visitField(ACC_PRIVATE, en.getKey(), "Ljava/lang/reflect/Type;", null, null);
fv.visitEnd(); fv.visitEnd();
@@ -1712,20 +1865,24 @@ public final class Rest {
fv.visitEnd(); fv.visitEnd();
} }
//classMap.put("mappings", mappingMaps); //不显示太多信息 //classMap.put("mappings", mappingMaps); //不显示太多信息
{ //toString函数 { //toString函数
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
//mv.setDebug(true); //mv.setDebug(true);
mv.visitLdcInsn(JsonConvert.root().convertTo(classMap)); mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, REST_TOSTRINGOBJ_FIELD_NAME, "Ljava/util/function/Supplier;");
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/function/Supplier", "get", "()Ljava/lang/Object;", true);
mv.visitTypeInsn(CHECKCAST, "java/lang/String");
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1); mv.visitMaxs(1, 1);
mv.visitEnd(); mv.visitEnd();
} }
cw.visitEnd(); cw.visitEnd();
newLoader.addClass(newDynName.replace('/', '.'), cw.toByteArray());
Class<?> newClazz = new RestClassLoader(loader).loadClass(newDynName.replace('/', '.'), cw.toByteArray());
try { try {
Class<?> newClazz = newLoader.findClass(newDynName.replace('/', '.'));
T obj = ((Class<T>) newClazz).getDeclaredConstructor().newInstance(); T obj = ((Class<T>) newClazz).getDeclaredConstructor().newInstance();
for (Map.Entry<String, org.redkale.util.Attribute> en : restAttributes.entrySet()) { for (Map.Entry<String, org.redkale.util.Attribute> en : restAttributes.entrySet()) {
Field attrField = newClazz.getDeclaredField(en.getKey()); Field attrField = newClazz.getDeclaredField(en.getKey());
@@ -1740,7 +1897,9 @@ public final class Rest {
for (int i = 0; i < restConverts.size(); i++) { for (int i = 0; i < restConverts.size(); i++) {
Field genField = newClazz.getDeclaredField(REST_JSONCONVERT_FIELD_PREFIX + (i + 1)); Field genField = newClazz.getDeclaredField(REST_JSONCONVERT_FIELD_PREFIX + (i + 1));
genField.setAccessible(true); genField.setAccessible(true);
genField.set(obj, createJsonConvert(restConverts.get(i))); Object[] rc = restConverts.get(i);
genField.set(obj, createJsonConvert((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]));
} }
Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME);
typesfield.setAccessible(true); typesfield.setAccessible(true);
@@ -1748,8 +1907,18 @@ public final class Rest {
paramtypeArray = paramtypes.toArray(paramtypeArray); paramtypeArray = paramtypes.toArray(paramtypeArray);
typesfield.set(obj, paramtypeArray); typesfield.set(obj, paramtypeArray);
Field tostringfield = newClazz.getDeclaredField(REST_TOSTRINGOBJ_FIELD_NAME);
tostringfield.setAccessible(true);
java.util.function.Supplier<String> sSupplier = () -> JsonConvert.root().convertTo(classMap);
tostringfield.set(obj, sSupplier);
Method restactMethod = newClazz.getDeclaredMethod("_createRestInnerActionEntry");
restactMethod.setAccessible(true);
Field tmpentrysfield = HttpServlet.class.getDeclaredField("_tmpentrys");
tmpentrysfield.setAccessible(true);
tmpentrysfield.set(obj, restactMethod.invoke(obj));
return obj; return obj;
} catch (Exception e) { } catch (Throwable e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@@ -1791,13 +1960,26 @@ public final class Rest {
private static class RestClassLoader extends ClassLoader { private static class RestClassLoader extends ClassLoader {
private Map<String, byte[]> classes = new HashMap<>();
public RestClassLoader(ClassLoader parent) { public RestClassLoader(ClassLoader parent) {
super(parent); super(parent);
} }
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = classes.get(name);
if (classData == null) return super.findClass(name);
return super.defineClass(name, classData, 0, classData.length);
}
public final Class<?> loadClass(String name, byte[] b) { public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length); return defineClass(name, b, 0, b.length);
} }
public final void addClass(String name, byte[] b) {
classes.put(name, b);
}
} }
private static class MappingEntry { private static class MappingEntry {
@@ -1839,6 +2021,8 @@ public final class Rest {
} }
} }
this.existsPound = pound; this.existsPound = pound;
this.newMethodName = this.name.replace('/', '$').replace('.', '_');
this.newActionClassName = "_Dyn_" + this.newMethodName + "_ActionHttpServlet";
} }
public final int methodidx; // _paramtypes 的下标从0开始 public final int methodidx; // _paramtypes 的下标从0开始
@@ -1847,6 +2031,10 @@ public final class Rest {
public final boolean ignore; public final boolean ignore;
public final String newMethodName;
public final String newActionClassName;
public final String name; public final String name;
public final String comment; public final String comment;
@@ -1861,6 +2049,8 @@ public final class Rest {
public final boolean existsPound; //是否包含#的参数 public final boolean existsPound; //是否包含#的参数
String mappingurl; //在生成方法时赋值, 供_createRestInnerActionEntry使用
@RestMapping() @RestMapping()
void mapping() { //用于获取Mapping 默认值 void mapping() { //用于获取Mapping 默认值
} }

View File

@@ -0,0 +1,43 @@
/*
* 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.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import org.redkale.convert.*;
/**
* 指定class某个字段的自定义序列化和反序列化策略。 <br>
* 只能依附在Service实现类的public方法上, 当方法的返回值以JSON输出时对指定类型的转换设定。 <br>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Repeatable(RestConvertCoder.RestConvertCoders.class)
public @interface RestConvertCoder {
Class type();
String field();
Class<? extends SimpledCoder> coder();
@Inherited
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@interface RestConvertCoders {
RestConvertCoder[] value();
}
}

View File

@@ -475,6 +475,35 @@ public abstract class WebSocket<G extends Serializable, T> {
return rs; return rs;
} }
/**
* 给指定userid的WebSocket节点发送操作
*
* @param action 操作参数
* @param userids Serializable[]
*
* @return 为0表示成功 其他值表示异常
*/
public final CompletableFuture<Integer> sendAction(final WebSocketAction action, Serializable... userids) {
if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL);
CompletableFuture<Integer> rs = _engine.node.sendAction(action, userids);
if (_engine.logger.isLoggable(Level.FINEST)) _engine.logger.finest("userids:" + Arrays.toString(userids) + " send websocket action(" + action + ")");
return rs;
}
/**
* 广播操作, 给所有人发操作指令
*
* @param action 操作参数
*
* @return 为0表示成功 其他值表示部分发送异常
*/
public final CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL);
CompletableFuture<Integer> rs = _engine.node.broadcastAction(action);
if (_engine.logger.isLoggable(Level.FINEST)) _engine.logger.finest("broadcast send websocket action(" + action + ")");
return rs;
}
/** /**
* 获取用户在线的SNCP节点地址列表不是分布式则返回元素数量为1且元素值为null的列表<br> * 获取用户在线的SNCP节点地址列表不是分布式则返回元素数量为1且元素值为null的列表<br>
* InetSocketAddress 为 SNCP节点地址 * InetSocketAddress 为 SNCP节点地址
@@ -529,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);
} }
/** /**
@@ -683,6 +712,18 @@ public abstract class WebSocket<G extends Serializable, T> {
return true; return true;
} }
/**
* WebSocket.broadcastAction时的操作
*
* @param action 操作参数
*
* @return CompletableFuture
*
*/
protected CompletableFuture<Integer> action(WebSocketAction action) {
return CompletableFuture.completedFuture(0);
}
/** /**
* WebSokcet连接成功后的回调方法 * WebSokcet连接成功后的回调方法
*/ */

View File

@@ -0,0 +1,58 @@
/*
* 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.http;
import java.io.Serializable;
import java.util.Map;
import org.redkale.convert.json.JsonConvert;
/**
* WebSocket.broadcastAction时的参数
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class WebSocketAction implements Serializable {
protected String action;
protected Map<String, String> attach;
public WebSocketAction() {
}
public WebSocketAction(String action) {
this.action = action;
}
public WebSocketAction(String action, Map<String, String> attach) {
this.action = action;
this.attach = attach;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public Map<String, String> getAttach() {
return attach;
}
public void setAttach(Map<String, String> attach) {
this.attach = attach;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}

View File

@@ -325,6 +325,54 @@ public class WebSocketEngine {
} }
} }
@Comment("给指定WebSocket连接用户发起操作指令")
public CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
CompletableFuture<Integer> future = null;
if (single) {
for (WebSocket websocket : websockets.values()) {
future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b);
}
} else {
for (List<WebSocket> list : websockets2.values()) {
for (WebSocket websocket : list) {
future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b);
}
}
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
}
@Comment("给指定用户组发送操作")
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Stream<? extends Serializable> userids) {
Object[] array = userids.toArray();
Serializable[] ss = new Serializable[array.length];
for (int i = 0; i < array.length; i++) {
ss[i] = (Serializable) array[i];
}
return sendAction(action, ss);
}
@Comment("给指定用户组发送操作")
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
CompletableFuture<Integer> future = null;
if (single) {
for (Serializable userid : userids) {
WebSocket websocket = websockets.get(userid);
if (websocket == null) continue;
future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b);
}
} else {
for (Serializable userid : userids) {
List<WebSocket> list = websockets2.get(userid);
if (list == null) continue;
for (WebSocket websocket : list) {
future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b);
}
}
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
}
@Comment("获取最大连接数") @Comment("获取最大连接数")
public int getLocalWsmaxconns() { public int getLocalWsmaxconns() {
return this.wsmaxconns; return this.wsmaxconns;

View File

@@ -60,7 +60,9 @@ public abstract class WebSocketNode {
protected Semaphore semaphore; protected Semaphore semaphore;
public void init(AnyValue conf) { public void init(AnyValue conf) {
if (sncpNodeAddresses != null) sncpNodeAddresses.initValueType(InetSocketAddress.class); if (sncpNodeAddresses != null && "memory".equals(sncpNodeAddresses.getType())) {
sncpNodeAddresses.initValueType(InetSocketAddress.class);
}
if (localEngine != null) { if (localEngine != null) {
int wsthreads = localEngine.wsthreads; int wsthreads = localEngine.wsthreads;
if (wsthreads == 0) wsthreads = Runtime.getRuntime().availableProcessors() * 8; if (wsthreads == 0) wsthreads = Runtime.getRuntime().availableProcessors() * 8;
@@ -82,7 +84,7 @@ public abstract class WebSocketNode {
//关掉所有本地本地WebSocket //关掉所有本地本地WebSocket
this.localEngine.getLocalWebSockets().forEach(g -> g.close()); this.localEngine.getLocalWebSockets().forEach(g -> g.close());
if (sncpNodeAddresses != null && localSncpAddress != null) { if (sncpNodeAddresses != null && localSncpAddress != null) {
sncpNodeAddresses.removeSetItem(SOURCE_SNCP_ADDRS_KEY, localSncpAddress); sncpNodeAddresses.removeSetItem(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class, localSncpAddress);
} }
} }
@@ -92,12 +94,18 @@ public abstract class WebSocketNode {
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> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action);
protected abstract CompletableFuture<Void> connect(Serializable userid, InetSocketAddress sncpAddr); protected abstract CompletableFuture<Void> connect(Serializable userid, InetSocketAddress sncpAddr);
protected abstract CompletableFuture<Void> disconnect(Serializable userid, InetSocketAddress sncpAddr); protected abstract CompletableFuture<Void> disconnect(Serializable userid, InetSocketAddress sncpAddr);
protected abstract CompletableFuture<Void> changeUserid(Serializable fromuserid, Serializable touserid, InetSocketAddress sncpAddr); protected abstract CompletableFuture<Void> changeUserid(Serializable fromuserid, Serializable touserid, InetSocketAddress sncpAddr);
protected abstract CompletableFuture<Boolean> existsWebSocket(Serializable userid, @RpcTargetAddress InetSocketAddress targetAddress);
protected abstract CompletableFuture<Integer> forceCloseWebSocket(Serializable userid, @RpcTargetAddress InetSocketAddress targetAddress); protected abstract CompletableFuture<Integer> forceCloseWebSocket(Serializable userid, @RpcTargetAddress InetSocketAddress targetAddress);
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
@@ -147,7 +155,7 @@ public abstract class WebSocketNode {
public CompletableFuture<Collection<InetSocketAddress>> getRpcNodeAddresses(final Serializable userid) { public CompletableFuture<Collection<InetSocketAddress>> getRpcNodeAddresses(final Serializable userid) {
if (this.sncpNodeAddresses != null) { if (this.sncpNodeAddresses != null) {
tryAcquireSemaphore(); tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> result = this.sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid); CompletableFuture<Collection<InetSocketAddress>> result = this.sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
if (semaphore != null) result.whenComplete((r, e) -> releaseSemaphore()); if (semaphore != null) result.whenComplete((r, e) -> releaseSemaphore());
return result; return result;
} }
@@ -180,23 +188,6 @@ public abstract class WebSocketNode {
}); });
} }
/**
* 判断指定用户是否WebSocket在线
*
* @param userid Serializable
*
* @return boolean
*/
public CompletableFuture<Boolean> existsWebSocket(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;
}
/** /**
* 获取在线用户总数 * 获取在线用户总数
* *
@@ -213,6 +204,59 @@ 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在线
*
* @param userid Serializable
*
* @return boolean
*/
@Local
public CompletableFuture<Boolean> existsWebSocket(final Serializable userid) {
CompletableFuture<Boolean> localFuture = null;
if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid));
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
//没有CacheSource就不会有分布式节点
return localFuture;
}
//远程节点关闭
tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
CompletableFuture<Boolean> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs);
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false);
CompletableFuture<Boolean> future = null;
for (InetSocketAddress addr : addrs) {
if (addr == null || addr.equals(localSncpAddress)) continue;
future = future == null ? remoteNode.existsWebSocket(userid, addr)
: future.thenCombine(remoteNode.existsWebSocket(userid, addr), (a, b) -> a | b);
}
return future == null ? CompletableFuture.completedFuture(false) : future;
});
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
/** /**
* 强制关闭用户WebSocket * 强制关闭用户WebSocket
* *
@@ -231,7 +275,7 @@ public abstract class WebSocketNode {
} }
//远程节点关闭 //远程节点关闭
tryAcquireSemaphore(); tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid); CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> { CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs);
@@ -509,7 +553,7 @@ public abstract class WebSocketNode {
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.broadcastMessage(wsrange, message, last);
tryAcquireSemaphore(); tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY); 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());
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> { CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast message (" + remoteMessage + ") on " + addrs); if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast message (" + remoteMessage + ") on " + addrs);
@@ -540,7 +584,7 @@ public abstract class WebSocketNode {
//远程节点发送消息 //远程节点发送消息
final Object remoteMessage = formatRemoteMessage(message); final Object remoteMessage = formatRemoteMessage(message);
tryAcquireSemaphore(); tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid); CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> { CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
if (addrs == null || addrs.isEmpty()) { if (addrs == null || addrs.isEmpty()) {
@@ -559,6 +603,90 @@ 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);
} }
/**
* 广播操作, 给所有人发操作
*
* @param action 操作参数
*
* @return 为0表示成功 其他值表示部分发送异常
*/
@Local
public CompletableFuture<Integer> broadcastAction(final WebSocketAction action) {
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
return this.localEngine.broadcastAction(action);
}
CompletableFuture<Integer> localFuture = this.localEngine == null ? null : this.localEngine.broadcastAction(action);
tryAcquireSemaphore();
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class);
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast action (" + action + ") on " + addrs);
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0);
CompletableFuture<Integer> future = null;
for (InetSocketAddress addr : addrs) {
if (addr == null || addr.equals(localSncpAddress)) continue;
future = future == null ? remoteNode.broadcastAction(addr, action)
: future.thenCombine(remoteNode.broadcastAction(addr, action), (a, b) -> a | b);
}
return future == null ? CompletableFuture.completedFuture(0) : future;
});
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
}
/**
* 向指定用户发送操作,先发送本地连接,再发送远程连接 <br>
* 如果当前WebSocketNode是远程模式此方法只发送远程连接
*
* @param action 操作参数
* @param userids Serializable[]
*
* @return 为0表示成功 其他值表示部分发送异常
*/
@Local
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
return this.localEngine.sendAction(action, userids);
}
CompletableFuture<Integer> future = null;
for (Serializable userid : userids) {
future = future == null ? sendOneAction(action, userid) : future.thenCombine(sendOneAction(action, userid), (a, b) -> a | b);
}
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
}
protected CompletableFuture<Integer> sendOneAction(final WebSocketAction action, final Serializable userid) {
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");
}
CompletableFuture<Integer> localFuture = null;
if (this.localEngine != null) localFuture = localEngine.sendAction(action, 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;
}
//远程节点发送操作
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.sendAction(addr, action, userid)
: future.thenCombine(remoteNode.sendAction(addr, action, 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 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;

View File

@@ -34,8 +34,6 @@ class WebSocketRunner implements Runnable {
protected final HttpContext context; protected final HttpContext context;
private ByteBuffer readBuffer;
volatile boolean closed = false; volatile boolean closed = false;
private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用 private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用
@@ -50,7 +48,6 @@ class WebSocketRunner implements Runnable {
this.webSocket = webSocket; this.webSocket = webSocket;
this.restMessageConsumer = messageConsumer; this.restMessageConsumer = messageConsumer;
this.channel = channel; this.channel = channel;
this.readBuffer = context.pollBuffer();
} }
@Override @Override
@@ -61,7 +58,7 @@ class WebSocketRunner implements Runnable {
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 +69,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(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,37 +98,36 @@ 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(), 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(); 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;
} }
@@ -197,7 +189,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");
@@ -302,8 +294,6 @@ class WebSocketRunner implements Runnable {
if (closed) return null; if (closed) return null;
closed = true; closed = true;
channel.dispose(); channel.dispose();
context.offerBuffer(readBuffer);
readBuffer = null;
CompletableFuture<Void> future = engine.removeThenClose(webSocket); CompletableFuture<Void> future = engine.removeThenClose(webSocket);
webSocket.onClose(code, reason); webSocket.onClose(code, reason);
return future; return future;

View File

@@ -106,6 +106,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 +148,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);
} }

View File

@@ -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
@@ -393,25 +392,25 @@ public final class SncpClient {
conn.write(newattachs, newattachs, this); conn.write(newattachs, newattachs, this);
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;

View File

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

View File

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

View File

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

View File

@@ -129,7 +129,7 @@ public class RetResult<T> {
*/ */
public RetResult<T> attach(String key, Object value) { public RetResult<T> attach(String key, Object value) {
if (this.attach == null) this.attach = new HashMap<>(); if (this.attach == null) this.attach = new HashMap<>();
boolean canstr = value != null && (value instanceof CharSequence || value.getClass().isPrimitive()); boolean canstr = value != null && (value instanceof CharSequence || value instanceof Number || value.getClass().isPrimitive());
this.attach.put(key, value == null ? null : (canstr ? String.valueOf(value) : JsonConvert.root().convertTo(value))); this.attach.put(key, value == null ? null : (canstr ? String.valueOf(value) : JsonConvert.root().convertTo(value)));
return this; return this;
} }

View File

@@ -67,6 +67,18 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
return this.localEngine.broadcastMessage(wsrange, message, last); return this.localEngine.broadcastMessage(wsrange, message, last);
} }
@Override
public CompletableFuture<Integer> sendAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action, Serializable userid) {
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
return this.localEngine.sendAction(action, userid);
}
@Override
public CompletableFuture<Integer> broadcastAction(@RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action) {
if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
return this.localEngine.broadcastAction(action);
}
/** /**
* 当用户连接到节点需要更新到CacheSource * 当用户连接到节点需要更新到CacheSource
* *
@@ -78,8 +90,8 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
@Override @Override
public CompletableFuture<Void> connect(Serializable userid, InetSocketAddress sncpAddr) { public CompletableFuture<Void> connect(Serializable userid, InetSocketAddress sncpAddr) {
tryAcquireSemaphore(); tryAcquireSemaphore();
CompletableFuture<Void> future = sncpNodeAddresses.appendSetItemAsync(SOURCE_SNCP_USERID_PREFIX + userid, sncpAddr); CompletableFuture<Void> future = sncpNodeAddresses.appendSetItemAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class, sncpAddr);
future = future.thenAccept((a) -> sncpNodeAddresses.appendSetItemAsync(SOURCE_SNCP_ADDRS_KEY, sncpAddr)); future = future.thenAccept((a) -> sncpNodeAddresses.appendSetItemAsync(SOURCE_SNCP_ADDRS_KEY, InetSocketAddress.class, sncpAddr));
if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore());
if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " connect from " + sncpAddr); if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " connect from " + sncpAddr);
return future; return future;
@@ -96,7 +108,7 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
@Override @Override
public CompletableFuture<Void> disconnect(Serializable userid, InetSocketAddress sncpAddr) { public CompletableFuture<Void> disconnect(Serializable userid, InetSocketAddress sncpAddr) {
tryAcquireSemaphore(); tryAcquireSemaphore();
CompletableFuture<Void> future = sncpNodeAddresses.removeSetItemAsync(SOURCE_SNCP_USERID_PREFIX + userid, sncpAddr); CompletableFuture<Void> future = sncpNodeAddresses.removeSetItemAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class, sncpAddr);
if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore());
if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " disconnect from " + sncpAddr); if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " disconnect from " + sncpAddr);
return future; return future;
@@ -114,13 +126,28 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
@Override @Override
public CompletableFuture<Void> changeUserid(Serializable olduserid, Serializable newuserid, InetSocketAddress sncpAddr) { public CompletableFuture<Void> changeUserid(Serializable olduserid, Serializable newuserid, InetSocketAddress sncpAddr) {
tryAcquireSemaphore(); tryAcquireSemaphore();
CompletableFuture<Void> future = sncpNodeAddresses.appendSetItemAsync(SOURCE_SNCP_USERID_PREFIX + newuserid, sncpAddr); CompletableFuture<Void> future = sncpNodeAddresses.appendSetItemAsync(SOURCE_SNCP_USERID_PREFIX + newuserid, InetSocketAddress.class, sncpAddr);
future = future.thenAccept((a) -> sncpNodeAddresses.removeSetItemAsync(SOURCE_SNCP_USERID_PREFIX + olduserid, sncpAddr)); future = future.thenAccept((a) -> sncpNodeAddresses.removeSetItemAsync(SOURCE_SNCP_USERID_PREFIX + olduserid, InetSocketAddress.class, sncpAddr));
if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore());
if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + olduserid + " changeUserid to " + newuserid + " from " + sncpAddr); if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + olduserid + " changeUserid to " + newuserid + " from " + sncpAddr);
return future; return future;
} }
/**
* 判断用户是否有WebSocket
*
* @param userid Serializable
* @param targetAddress InetSocketAddress
*
* @return 无返回值
*/
@Override
public CompletableFuture<Boolean> existsWebSocket(Serializable userid, @RpcTargetAddress InetSocketAddress targetAddress) {
if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " existsWebSocket from " + targetAddress);
if (localEngine == null) return CompletableFuture.completedFuture(false);
return CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid));
}
/** /**
* 强制关闭用户的WebSocket * 强制关闭用户的WebSocket
* *

View File

@@ -27,9 +27,9 @@ import org.redkale.util.*;
* *
* @author zhangjx * @author zhangjx
*/ */
@SuppressWarnings("unchecked")
@Local @Local
@AutoLoad(false) @AutoLoad(false)
@SuppressWarnings("unchecked")
@ResourceType(CacheSource.class) @ResourceType(CacheSource.class)
public class CacheMemorySource<V extends Object> extends AbstractService implements CacheSource<V>, Service, AutoCloseable, Resourcable { public class CacheMemorySource<V extends Object> extends AbstractService implements CacheSource<V>, Service, AutoCloseable, Resourcable {
@@ -340,6 +340,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return (V) entry.objectValue; return (V) entry.objectValue;
} }
@Override
public <T> T get(final String key, final Type type) {
return (T) get(key);
}
@Override @Override
public String getString(String key) { public String getString(String key) {
if (key == null) return null; if (key == null) return null;
@@ -361,6 +366,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.supplyAsync(() -> get(key), getExecutor()); return CompletableFuture.supplyAsync(() -> get(key), getExecutor());
} }
@Override
public <T> CompletableFuture<T> getAsync(final String key, final Type type) {
return CompletableFuture.supplyAsync(() -> (T) get(key), getExecutor());
}
@Override @Override
public CompletableFuture<String> getStringAsync(final String key) { public CompletableFuture<String> getStringAsync(final String key) {
return CompletableFuture.supplyAsync(() -> getString(key), getExecutor()); return CompletableFuture.supplyAsync(() -> getString(key), getExecutor());
@@ -385,6 +395,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return (V) entry.objectValue; return (V) entry.objectValue;
} }
@Override
public <T> T getAndRefresh(final String key, final int expireSeconds, final Type type) {
return (T) getAndRefresh(key, expireSeconds);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -415,6 +430,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.supplyAsync(() -> getAndRefresh(key, expireSeconds), getExecutor()); return CompletableFuture.supplyAsync(() -> getAndRefresh(key, expireSeconds), getExecutor());
} }
@Override
public <T> CompletableFuture<T> getAndRefreshAsync(final String key, final int expireSeconds, final Type type) {
return CompletableFuture.supplyAsync(() -> getAndRefresh(key, expireSeconds, type), getExecutor());
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<String> getStringAndRefreshAsync(final String key, final int expireSeconds) { public CompletableFuture<String> getStringAndRefreshAsync(final String key, final int expireSeconds) {
@@ -462,6 +482,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
set(CacheEntryType.OBJECT, key, value); set(CacheEntryType.OBJECT, key, value);
} }
@Override
public <T> void set(String key, Type type, T value) {
set(CacheEntryType.OBJECT, key, value);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void setString(String key, String value) { public void setString(String key, String value) {
@@ -480,6 +505,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.runAsync(() -> set(key, value), getExecutor()).whenComplete(futureCompleteConsumer); return CompletableFuture.runAsync(() -> set(key, value), getExecutor()).whenComplete(futureCompleteConsumer);
} }
@Override
public <T> CompletableFuture<Void> setAsync(String key, Type type, T value) {
return CompletableFuture.runAsync(() -> set(key, type, value), getExecutor()).whenComplete(futureCompleteConsumer);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<Void> setStringAsync(String key, String value) { public CompletableFuture<Void> setStringAsync(String key, String value) {
@@ -511,6 +541,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
set(CacheEntryType.OBJECT, expireSeconds, key, value); set(CacheEntryType.OBJECT, expireSeconds, key, value);
} }
@Override
public <T> void set(final int expireSeconds, String key, Type type, T value) {
set(CacheEntryType.OBJECT, expireSeconds, key, value);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void setString(int expireSeconds, String key, String value) { public void setString(int expireSeconds, String key, String value) {
@@ -529,6 +564,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.runAsync(() -> set(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer); return CompletableFuture.runAsync(() -> set(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer);
} }
@Override
public <T> CompletableFuture<Void> setAsync(int expireSeconds, String key, Type type, T value) {
return CompletableFuture.runAsync(() -> set(expireSeconds, key, type, value), getExecutor()).whenComplete(futureCompleteConsumer);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<Void> setStringAsync(int expireSeconds, String key, String value) { public CompletableFuture<Void> setStringAsync(int expireSeconds, String key, String value) {
@@ -632,6 +672,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return (Collection<V>) get(key); return (Collection<V>) get(key);
} }
@Override
public <T> Collection<T> getCollection(final String key, final Type componentType) {
return (Collection<T>) get(key);
}
@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);
@@ -647,6 +692,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.supplyAsync(() -> getCollection(key), getExecutor()); return CompletableFuture.supplyAsync(() -> getCollection(key), getExecutor());
} }
@Override
public CompletableFuture<Collection<V>> getCollectionAsync(final String key, final Type componentType) {
return CompletableFuture.supplyAsync(() -> getCollection(key, componentType), 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());
@@ -674,6 +724,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return (Collection<V>) getAndRefresh(key, expireSeconds); return (Collection<V>) getAndRefresh(key, expireSeconds);
} }
@Override
public <T> Collection<T> getCollectionAndRefresh(final String key, final int expireSeconds, final Type componentType) {
return (Collection<T>) getAndRefresh(key, expireSeconds, componentType);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public Collection<String> getStringCollectionAndRefresh(final String key, final int expireSeconds) { public Collection<String> getStringCollectionAndRefresh(final String key, final int expireSeconds) {
@@ -686,11 +741,22 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return list != null && list.contains(value); return list != null && list.contains(value);
} }
@Override
public <T> boolean existsSetItem(final String key, final Type type, final T value) {
Collection list = getCollection(key);
return list != null && list.contains(value);
}
@Override @Override
public CompletableFuture<Boolean> existsSetItemAsync(final String key, final V value) { public CompletableFuture<Boolean> existsSetItemAsync(final String key, final V value) {
return CompletableFuture.supplyAsync(() -> existsSetItem(key, value), getExecutor()); return CompletableFuture.supplyAsync(() -> existsSetItem(key, value), getExecutor());
} }
@Override
public <T> CompletableFuture<Boolean> existsSetItemAsync(final String key, final Type type, final T value) {
return CompletableFuture.supplyAsync(() -> existsSetItem(key, type, value), getExecutor());
}
@Override @Override
public boolean existsStringSetItem(final String key, final String value) { public boolean existsStringSetItem(final String key, final String value) {
Collection<String> list = getStringCollection(key); Collection<String> list = getStringCollection(key);
@@ -725,6 +791,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.supplyAsync(() -> getCollectionAndRefresh(key, expireSeconds), getExecutor()); return CompletableFuture.supplyAsync(() -> getCollectionAndRefresh(key, expireSeconds), getExecutor());
} }
@Override
public <T> CompletableFuture<Collection<T>> getCollectionAndRefreshAsync(final String key, final int expireSeconds, final Type componentType) {
return CompletableFuture.supplyAsync(() -> getCollectionAndRefresh(key, expireSeconds, componentType), getExecutor());
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<Collection<String>> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds) { public CompletableFuture<Collection<String>> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds) {
@@ -757,6 +828,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
appendListItem(CacheEntryType.OBJECT_LIST, key, value); appendListItem(CacheEntryType.OBJECT_LIST, key, value);
} }
@Override
public <T> void appendListItem(String key, Type componentType, T value) {
appendListItem(CacheEntryType.OBJECT_LIST, key, value);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void appendStringListItem(String key, String value) { public void appendStringListItem(String key, String value) {
@@ -775,6 +851,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.runAsync(() -> appendListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); return CompletableFuture.runAsync(() -> appendListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer);
} }
@Override
public <T> CompletableFuture<Void> appendListItemAsync(final String key, final Type componentType, final T value) {
return CompletableFuture.runAsync(() -> appendListItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<Void> appendStringListItemAsync(final String key, final String value) { public CompletableFuture<Void> appendStringListItemAsync(final String key, final String value) {
@@ -796,6 +877,14 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
entry.listValue.remove(value); entry.listValue.remove(value);
} }
@Override
public <T> void removeListItem(String key, final Type componentType, T value) {
if (key == null) return;
CacheEntry entry = container.get(key);
if (entry == null || entry.listValue == null) return;
entry.listValue.remove(value);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void removeStringListItem(String key, String value) { public void removeStringListItem(String key, String value) {
@@ -820,6 +909,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.runAsync(() -> removeListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); return CompletableFuture.runAsync(() -> removeListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer);
} }
@Override
public <T> CompletableFuture<Void> removeListItemAsync(final String key, final Type componentType, T value) {
return CompletableFuture.runAsync(() -> removeListItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<Void> removeStringListItemAsync(final String key, final String value) { public CompletableFuture<Void> removeStringListItemAsync(final String key, final String value) {
@@ -852,6 +946,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
appendSetItem(CacheEntryType.OBJECT_SET, key, value); appendSetItem(CacheEntryType.OBJECT_SET, key, value);
} }
@Override
public <T> void appendSetItem(String key, final Type componentType, T value) {
appendSetItem(CacheEntryType.OBJECT_SET, key, value);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void appendStringSetItem(String key, String value) { public void appendStringSetItem(String key, String value) {
@@ -870,6 +969,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.runAsync(() -> appendSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); return CompletableFuture.runAsync(() -> appendSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer);
} }
@Override
public <T> CompletableFuture<Void> appendSetItemAsync(final String key, final Type componentType, T value) {
return CompletableFuture.runAsync(() -> appendSetItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<Void> appendStringSetItemAsync(final String key, final String value) { public CompletableFuture<Void> appendStringSetItemAsync(final String key, final String value) {
@@ -891,6 +995,14 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
entry.csetValue.remove(value); entry.csetValue.remove(value);
} }
@Override
public <T> void removeSetItem(String key, Type type, T value) {
if (key == null) return;
CacheEntry entry = container.get(key);
if (entry == null || entry.csetValue == null) return;
entry.csetValue.remove(value);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void removeStringSetItem(String key, String value) { public void removeStringSetItem(String key, String value) {
@@ -915,6 +1027,11 @@ public class CacheMemorySource<V extends Object> extends AbstractService impleme
return CompletableFuture.runAsync(() -> removeSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); return CompletableFuture.runAsync(() -> removeSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer);
} }
@Override
public <T> CompletableFuture<Void> removeSetItemAsync(final String key, final Type componentType, final T value) {
return CompletableFuture.runAsync(() -> removeSetItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public CompletableFuture<Void> removeStringSetItemAsync(final String key, final String value) { public CompletableFuture<Void> removeStringSetItemAsync(final String key, final String value) {

View File

@@ -42,6 +42,8 @@ public interface CacheSource<V extends Object> {
public V get(final String key); public V get(final String key);
public <T> T get(final String key, final Type type);
default V getIfAbsent(final String key, Function<String, ? extends V> mappingFunction) { default V getIfAbsent(final String key, Function<String, ? extends V> mappingFunction) {
V rs = get(key); V rs = get(key);
if (rs == null) { if (rs == null) {
@@ -53,6 +55,8 @@ public interface CacheSource<V extends Object> {
public V getAndRefresh(final String key, final int expireSeconds); public V getAndRefresh(final String key, final int expireSeconds);
public <T> T getAndRefresh(final String key, final int expireSeconds, final Type type);
default V getAndRefreshIfAbsent(final String key, final int expireSeconds, Function<String, ? extends V> mappingFunction) { default V getAndRefreshIfAbsent(final String key, final int expireSeconds, Function<String, ? extends V> mappingFunction) {
V rs = getAndRefresh(key, expireSeconds); V rs = getAndRefresh(key, expireSeconds);
if (rs == null) { if (rs == null) {
@@ -66,8 +70,12 @@ public interface CacheSource<V extends Object> {
public void set(final String key, final V value); public void set(final String key, final V value);
public <T> void set(final String key, final Type type, final T value);
public void set(final int expireSeconds, final String key, final V value); public void set(final int expireSeconds, final String key, final V value);
public <T> void set(final int expireSeconds, final String key, final Type type, final T value);
public void setExpireSeconds(final String key, final int expireSeconds); public void setExpireSeconds(final String key, final int expireSeconds);
public void remove(final String key); public void remove(final String key);
@@ -82,10 +90,14 @@ public interface CacheSource<V extends Object> {
public Collection<V> getCollection(final String key); public Collection<V> getCollection(final String key);
public <T> Collection<T> getCollection(final String key, final Type componentType);
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);
public <T> Collection<T> getCollectionAndRefresh(final String key, final int expireSeconds, final Type componentType);
public void appendListItem(final String key, final V value); public void appendListItem(final String key, final V value);
public void removeListItem(final String key, final V value); public void removeListItem(final String key, final V value);
@@ -96,6 +108,16 @@ public interface CacheSource<V extends Object> {
public void removeSetItem(final String key, final V value); public void removeSetItem(final String key, final V value);
public <T> void appendListItem(final String key, final Type componentType, final T value);
public <T> void removeListItem(final String key, final Type componentType, final T value);
public <T> boolean existsSetItem(final String key, final Type componentType, final T value);
public <T> void appendSetItem(final String key, final Type componentType, final T value);
public <T> void removeSetItem(final String key, final Type componentType, final T value);
public List<String> queryKeys(); public List<String> queryKeys();
public List<String> queryKeysStartsWith(String startsWith); public List<String> queryKeysStartsWith(String startsWith);
@@ -153,6 +175,8 @@ public interface CacheSource<V extends Object> {
//---------------------- CompletableFuture 异步版 --------------------------------- //---------------------- CompletableFuture 异步版 ---------------------------------
public CompletableFuture<Boolean> existsAsync(final String key); public CompletableFuture<Boolean> existsAsync(final String key);
public <T> CompletableFuture<T> getAsync(final String key, final Type type);
public CompletableFuture<V> getAsync(final String key); public CompletableFuture<V> getAsync(final String key);
default CompletableFuture<V> getIfAbsentAsync(final String key, Function<String, ? extends V> mappingFunction) { default CompletableFuture<V> getIfAbsentAsync(final String key, Function<String, ? extends V> mappingFunction) {
@@ -170,6 +194,8 @@ public interface CacheSource<V extends Object> {
public CompletableFuture<V> getAndRefreshAsync(final String key, final int expireSeconds); public CompletableFuture<V> getAndRefreshAsync(final String key, final int expireSeconds);
public <T> CompletableFuture<T> getAndRefreshAsync(final String key, final int expireSeconds, final Type type);
default CompletableFuture<V> getAndRefreshIfAbsentAsync(final String key, final int expireSeconds, Function<String, ? extends V> mappingFunction) { default CompletableFuture<V> getAndRefreshIfAbsentAsync(final String key, final int expireSeconds, Function<String, ? extends V> mappingFunction) {
return getAndRefreshAsync(key, expireSeconds).thenCompose((V rs) -> { return getAndRefreshAsync(key, expireSeconds).thenCompose((V rs) -> {
if (rs == null) { if (rs == null) {
@@ -187,8 +213,12 @@ public interface CacheSource<V extends Object> {
public CompletableFuture<Void> setAsync(final String key, final V value); public CompletableFuture<Void> setAsync(final String key, final V value);
public <T> CompletableFuture<Void> setAsync(final String key, final Type type, final T value);
public CompletableFuture<Void> setAsync(final int expireSeconds, final String key, final V value); public CompletableFuture<Void> setAsync(final int expireSeconds, final String key, final V value);
public <T> CompletableFuture<Void> setAsync(final int expireSeconds, final String key, final Type type, final T value);
public CompletableFuture<Void> setExpireSecondsAsync(final String key, final int expireSeconds); public CompletableFuture<Void> setExpireSecondsAsync(final String key, final int expireSeconds);
public CompletableFuture<Void> removeAsync(final String key); public CompletableFuture<Void> removeAsync(final String key);
@@ -203,10 +233,14 @@ public interface CacheSource<V extends Object> {
public CompletableFuture<Collection<V>> getCollectionAsync(final String key); public CompletableFuture<Collection<V>> getCollectionAsync(final String key);
public <T> CompletableFuture<Collection<T>> getCollectionAsync(final String key, final Type componentType);
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);
public <T> CompletableFuture<Collection<T>> getCollectionAndRefreshAsync(final String key, final int expireSeconds, final Type componentType);
public CompletableFuture<Void> appendListItemAsync(final String key, final V value); public CompletableFuture<Void> appendListItemAsync(final String key, final V value);
public CompletableFuture<Void> removeListItemAsync(final String key, final V value); public CompletableFuture<Void> removeListItemAsync(final String key, final V value);
@@ -217,6 +251,16 @@ public interface CacheSource<V extends Object> {
public CompletableFuture<Void> removeSetItemAsync(final String key, final V value); public CompletableFuture<Void> removeSetItemAsync(final String key, final V value);
public <T> CompletableFuture<Void> appendListItemAsync(final String key, final Type componentType, final T value);
public <T> CompletableFuture<Void> removeListItemAsync(final String key, final Type componentType, final T value);
public <T> CompletableFuture<Boolean> existsSetItemAsync(final String key, final Type componentType, final T value);
public <T> CompletableFuture<Void> appendSetItemAsync(final String key, final Type componentType, final T value);
public <T> CompletableFuture<Void> removeSetItemAsync(final String key, final Type componentType, final T value);
public CompletableFuture<List<String>> queryKeysAsync(); public CompletableFuture<List<String>> queryKeysAsync();
public CompletableFuture<List<String>> queryKeysStartsWithAsync(String startsWith); public CompletableFuture<List<String>> queryKeysStartsWithAsync(String startsWith);

View File

@@ -167,27 +167,35 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
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 : values) {
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 value) throws SQLException {
int i = 0;
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(++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) && !(value 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;
@@ -224,21 +232,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
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 : values) {
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) { //打印调试信息
@@ -434,6 +428,9 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
if (blob != null) val = blob.getBytes(1, (int) blob.length()); if (blob != null) val = blob.getBytes(1, (int) blob.length());
} else { } else {
val = (Serializable) set.getObject(1); val = (Serializable) set.getObject(1);
if (val != null && !CharSequence.class.isAssignableFrom(attr.type()) && (val instanceof CharSequence)) {
val = info.jsonConvert.convertFrom(attr.genericType(), val.toString());
}
} }
} }
set.close(); set.close();

View File

@@ -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()) || readprop == null) {
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();

View File

@@ -785,6 +785,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
List<byte[]> blobs = null; List<byte[]> blobs = null;
int index = 0; int index = 0;
for (ColumnValue col : values) { for (ColumnValue col : values) {
if (col == null) continue;
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn()); Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) throw new RuntimeException(info.getType() + " cannot found column " + col.getColumn()); if (attr == null) throw new RuntimeException(info.getType() + " cannot found column " + col.getColumn());
if (setsql.length() > 0) setsql.append(", "); if (setsql.length() > 0) setsql.append(", ");
@@ -797,6 +798,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
setsql.append(c).append(" = ").append(info.formatSQLValue(c, col)); setsql.append(c).append(" = ").append(info.formatSQLValue(c, col));
} }
} }
if (setsql.length() < 1) return CompletableFuture.completedFuture(0);
String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id); String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (blobs == null) return updateDB(info, null, sql, false); if (blobs == null) return updateDB(info, null, sql, false);
return updateDB(info, null, sql, true, blobs.toArray()); return updateDB(info, null, sql, true, blobs.toArray());
@@ -865,6 +867,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
int index = 0; int index = 0;
String alias = "postgresql".equals(writePool.dbtype) ? null : "a"; //postgresql的BUG UPDATE的SET中不能含别名 String alias = "postgresql".equals(writePool.dbtype) ? null : "a"; //postgresql的BUG UPDATE的SET中不能含别名
for (ColumnValue col : values) { for (ColumnValue col : values) {
if (col == null) continue;
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn()); Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue; if (attr == null) continue;
if (setsql.length() > 0) setsql.append(", "); if (setsql.length() > 0) setsql.append(", ");
@@ -877,6 +880,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
setsql.append(c).append(" = ").append(info.formatSQLValue(c, col)); setsql.append(c).append(" = ").append(info.formatSQLValue(c, col));
} }
} }
if (setsql.length() < 1) return CompletableFuture.completedFuture(0);
Map<Class, String> joinTabalis = node.getJoinTabalis(); Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis); CharSequence where = node.createSQLExpress(info, joinTabalis);
@@ -1060,6 +1064,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>(); final List<ColumnValue> cols = new ArrayList<>();
for (ColumnValue col : values) { for (ColumnValue col : values) {
if (col == null) continue;
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn()); Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue; if (attr == null) continue;
attrs.add(attr); attrs.add(attr);
@@ -1076,6 +1081,7 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
final List<Attribute<T, Serializable>> attrs = new ArrayList<>(); final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>(); final List<ColumnValue> cols = new ArrayList<>();
for (ColumnValue col : values) { for (ColumnValue col : values) {
if (col == null) continue;
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn()); Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue; if (attr == null) continue;
attrs.add(attr); attrs.add(attr);

View File

@@ -14,6 +14,7 @@ import java.util.concurrent.atomic.*;
import java.util.function.*; import java.util.function.*;
import java.util.logging.*; import java.util.logging.*;
import javax.persistence.*; import javax.persistence.*;
import org.redkale.convert.json.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
@@ -28,6 +29,8 @@ import org.redkale.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class EntityInfo<T> { public final class EntityInfo<T> {
private static final JsonConvert DEFAULT_JSON_CONVERT = JsonFactory.create().skipAllIgnore(true).getConvert();
//全局静态资源 //全局静态资源
private static final ConcurrentHashMap<Class, EntityInfo> entityInfos = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Class, EntityInfo> entityInfos = new ConcurrentHashMap<>();
@@ -40,6 +43,9 @@ public final class EntityInfo<T> {
//类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null //类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null
final String table; final String table;
//JsonConvert
final JsonConvert jsonConvert;
//Entity构建器 //Entity构建器
private final Creator<T> creator; private final Creator<T> creator;
@@ -330,6 +336,25 @@ public final class EntityInfo<T> {
} }
} while ((cltmp = cltmp.getSuperclass()) != Object.class); } while ((cltmp = cltmp.getSuperclass()) != Object.class);
if (idAttr0 == null) throw new RuntimeException(type.getName() + " have no primary column by @javax.persistence.Id"); if (idAttr0 == null) throw new RuntimeException(type.getName() + " have no primary column by @javax.persistence.Id");
cltmp = type;
JsonConvert convert = DEFAULT_JSON_CONVERT;
do {
for (Method method : cltmp.getDeclaredMethods()) {
if (method.getAnnotation(SourceConvert.class) == null) continue;
if (!Modifier.isStatic(method.getModifiers())) throw new RuntimeException("@SourceConvert method(" + method + ") must be static");
if (method.getReturnType() != JsonConvert.class) throw new RuntimeException("@SourceConvert method(" + method + ") must be return JsonConvert.class");
if (method.getParameterCount() > 0) throw new RuntimeException("@SourceConvert method(" + method + ") must be 0 parameter");
try {
method.setAccessible(true);
convert = (JsonConvert) method.invoke(null);
} catch (Exception e) {
throw new RuntimeException(method + " invoke error", e);
}
if (convert != null) break;
}
} while ((cltmp = cltmp.getSuperclass()) != Object.class);
this.jsonConvert = convert == null ? DEFAULT_JSON_CONVERT : convert;
this.primary = idAttr0; this.primary = idAttr0;
this.aliasmap = aliasmap0; this.aliasmap = aliasmap0;
this.attributes = attributeMap.values().toArray(new Attribute[attributeMap.size()]); this.attributes = attributeMap.values().toArray(new Attribute[attributeMap.size()]);
@@ -929,6 +954,9 @@ public final class EntityInfo<T> {
if (value == null) return null; if (value == null) return null;
if (value instanceof CharSequence) { if (value instanceof CharSequence) {
return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\'').toString(); return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\'').toString();
} else if (!(value instanceof Number) && !(value instanceof java.util.Date)
&& !value.getClass().getName().startsWith("java.sql.") && !value.getClass().getName().startsWith("java.time.")) {
return new StringBuilder().append('\'').append(jsonConvert.convertTo(value).replace("'", "\\'")).append('\'').toString();
} }
return String.valueOf(value); return String.valueOf(value);
} }
@@ -1026,6 +1054,8 @@ public final class EntityInfo<T> {
} else { } else {
o = new AtomicLong(); o = new AtomicLong();
} }
} else if (o != null && !t.isAssignableFrom(o.getClass()) && o instanceof CharSequence) {
o = ((CharSequence) o).length() == 0 ? null : jsonConvert.convertFrom(attr.genericType(), o.toString());
} }
} }
return o; return o;

View File

@@ -82,11 +82,23 @@ public class FilterJoinNode extends FilterNode {
return new FilterJoinNode(joinClass, joinColumns, column, express, itemand, value); return new FilterJoinNode(joinClass, joinColumns, column, express, itemand, value);
} }
@Override
public FilterJoinNode copy() {
FilterJoinNode node = (FilterJoinNode) copy(new FilterJoinNode());
node.joinClass = this.joinClass;
node.joinEntity = this.joinEntity;
if (this.joinColumns != null) {
node.joinColumns = new String[this.joinColumns.length];
System.arraycopy(this.joinColumns, 0, node.joinColumns, 0, this.joinColumns.length);
}
return node;
}
@Override @Override
protected FilterNode any(final FilterNode node0, boolean signor) { protected FilterNode any(final FilterNode node0, boolean signor) {
Objects.requireNonNull(node0); Objects.requireNonNull(node0);
if (!(node0 instanceof FilterJoinNode)) { if (!(node0 instanceof FilterJoinNode)) {
throw new IllegalArgumentException(this + (signor ? " or " : " and ") + " a node but " + String.valueOf(node0) + "is not a " + FilterJoinNode.class.getSimpleName()); throw new IllegalArgumentException(this + (signor ? " or " : " and ") + " a node but " + String.valueOf(node0) + " is not a " + FilterJoinNode.class.getSimpleName());
} }
final FilterJoinNode node = (FilterJoinNode) node0; final FilterJoinNode node = (FilterJoinNode) node0;
if (this.nodes == null) { if (this.nodes == null) {
@@ -99,7 +111,7 @@ public class FilterJoinNode extends FilterNode {
if (this.column == null) this.or = signor; if (this.column == null) this.or = signor;
return this; return this;
} }
this.nodes = new FilterNode[]{new FilterJoinNode(node), node}; this.nodes = new FilterNode[]{new FilterJoinNode(this), node};
this.column = null; this.column = null;
this.express = null; this.express = null;
this.itemand = true; this.itemand = true;

View File

@@ -25,6 +25,8 @@ import org.redkale.util.*;
*/ */
public class FilterNode { //FilterNode 不能实现Serializable接口 否则DataSource很多重载接口会出现冲突 public class FilterNode { //FilterNode 不能实现Serializable接口 否则DataSource很多重载接口会出现冲突
protected boolean readOnly;
protected String column; protected String column;
protected FilterExpress express; protected FilterExpress express;
@@ -80,6 +82,36 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
this.value = val; this.value = val;
} }
public FilterNode copy() {
return copy(new FilterNode());
}
protected FilterNode copy(FilterNode node) {
node.readOnly = this.readOnly;
node.column = this.column;
node.express = this.express;
node.value = this.value;
node.itemand = this.itemand;
node.or = this.or;
if (this.nodes != null) {
node.nodes = new FilterNode[this.nodes.length];
for (int i = 0; i < node.nodes.length; i++) {
node.nodes[i] = this.nodes[i] == null ? null : this.nodes[i].copy();
}
}
return node;
}
public FilterNode asReadOnly() {
this.readOnly = true;
return this;
}
public FilterNode readOnly(boolean readOnly) {
this.readOnly = readOnly;
return this;
}
public long findLongValue(final String col, long defValue) { public long findLongValue(final String col, long defValue) {
Serializable val = findValue(col); Serializable val = findValue(col);
return val == null ? defValue : ((Number) val).longValue(); return val == null ? defValue : ((Number) val).longValue();
@@ -95,7 +127,7 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
} }
public Serializable findValue(final String col) { public Serializable findValue(final String col) {
if (this.column.equals(col)) return this.value; if (this.column != null && this.column.equals(col)) return this.value;
if (this.nodes == null) return null; if (this.nodes == null) return null;
for (FilterNode n : this.nodes) { for (FilterNode n : this.nodes) {
if (n == null) continue; if (n == null) continue;
@@ -138,6 +170,7 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
} }
protected FilterNode any(FilterNode node, boolean signor) { protected FilterNode any(FilterNode node, boolean signor) {
if (this.readOnly) throw new RuntimeException("FilterNode(" + this + ") is ReadOnly");
Objects.requireNonNull(node); Objects.requireNonNull(node);
if (this.column == null) { if (this.column == null) {
this.column = node.column; this.column = node.column;
@@ -1861,6 +1894,14 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
this.value = value; this.value = value;
} }
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
public final boolean isOr() { public final boolean isOr() {
return or; return or;
} }

View File

@@ -86,6 +86,8 @@ public class PoolJdbcSource extends PoolSource<Connection> {
source0 = "org.postgresql.Driver"; source0 = "org.postgresql.Driver";
} else if (url.startsWith("jdbc:microsoft:sqlserver:")) { } else if (url.startsWith("jdbc:microsoft:sqlserver:")) {
source0 = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; source0 = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
} else if (url.startsWith("jdbc:h2")) {
source0 = "org.h2.Driver";
} }
} }
if (source0 != null && source0.contains("Driver")) { //为了兼容JPA的配置文件 if (source0 != null && source0.contains("Driver")) { //为了兼容JPA的配置文件
@@ -111,6 +113,9 @@ public class PoolJdbcSource extends PoolSource<Connection> {
case "com.microsoft.sqlserver.jdbc.SQLServerDriver": case "com.microsoft.sqlserver.jdbc.SQLServerDriver":
source = "com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource"; source = "com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource";
break; break;
case "org.h2.Driver":
source = "org.h2.jdbcx.JdbcDataSource";
break;
} }
} }
final Class clazz = Thread.currentThread().getContextClassLoader().loadClass(source); final Class clazz = Thread.currentThread().getContextClassLoader().loadClass(source);

View File

@@ -123,6 +123,7 @@ public abstract class PoolSource<DBChannel> {
} }
protected void parseAddressAndDbnameAndAttrs() { protected void parseAddressAndDbnameAndAttrs() {
if (this.url.startsWith("jdbc:h2:")) return;
String url0 = this.url.substring(this.url.indexOf("://") + 3); String url0 = this.url.substring(this.url.indexOf("://") + 3);
int pos = url0.indexOf('?'); //127.0.0.1:5432/db?charset=utr8&xxx=yy int pos = url0.indexOf('?'); //127.0.0.1:5432/db?charset=utr8&xxx=yy
if (pos > 0) { if (pos > 0) {

View File

@@ -133,7 +133,7 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
}); });
} }
return AsyncConnection.createTCP(group, this.servaddr, this.readTimeoutSeconds, this.writeTimeoutSeconds).thenCompose(conn -> { return AsyncConnection.createTCP(bufferPool, group, this.servaddr, this.readTimeoutSeconds, this.writeTimeoutSeconds).thenCompose(conn -> {
conn.beforeCloseListener((c) -> { conn.beforeCloseListener((c) -> {
semaphore.release(); semaphore.release();
closeCounter.incrementAndGet(); closeCounter.incrementAndGet();
@@ -143,12 +143,11 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
final ByteBuffer buffer = reqConnectBuffer(conn); final ByteBuffer buffer = reqConnectBuffer(conn);
if (buffer == null) { if (buffer == null) {
final ByteBuffer rbuffer = bufferPool.get(); conn.read(new CompletionHandler<Integer, ByteBuffer>() {
conn.read(rbuffer, null, new CompletionHandler<Integer, Void>() {
@Override @Override
public void completed(Integer result, Void attachment2) { public void completed(Integer result, ByteBuffer rbuffer) {
if (result < 0) { if (result < 0) {
failed(new SQLException("Read Buffer Error"), attachment2); failed(new SQLException("Read Buffer Error"), rbuffer);
return; return;
} }
rbuffer.flip(); rbuffer.flip();
@@ -156,8 +155,8 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
} }
@Override @Override
public void failed(Throwable exc, Void attachment2) { public void failed(Throwable exc, ByteBuffer rbuffer) {
bufferPool.accept(rbuffer); conn.offerBuffer(rbuffer);
future.completeExceptionally(exc); future.completeExceptionally(exc);
conn.dispose(); conn.dispose();
} }
@@ -175,11 +174,12 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
return; return;
} }
buffer.clear(); buffer.clear();
conn.read(buffer, null, new CompletionHandler<Integer, Void>() { conn.setReadBuffer(buffer);
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
@Override @Override
public void completed(Integer result, Void attachment2) { public void completed(Integer result, ByteBuffer rbuffer) {
if (result < 0) { if (result < 0) {
failed(new SQLException("Read Buffer Error"), attachment2); failed(new SQLException("Read Buffer Error"), rbuffer);
return; return;
} }
buffer.flip(); buffer.flip();
@@ -187,8 +187,8 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
} }
@Override @Override
public void failed(Throwable exc, Void attachment2) { public void failed(Throwable exc, ByteBuffer rbuffer) {
bufferPool.accept(buffer); conn.offerBuffer(rbuffer);
future.completeExceptionally(exc); future.completeExceptionally(exc);
conn.dispose(); conn.dispose();
} }

Some files were not shown because too many files have changed in this diff Show More