Compare commits
324 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b69e7d02b | ||
|
|
02a10bf014 | ||
|
|
004b83172e | ||
|
|
fee4555cef | ||
|
|
758bd7de72 | ||
|
|
b2dd366640 | ||
|
|
934c82eadd | ||
|
|
c7ed6574cc | ||
|
|
2ea2667fa7 | ||
|
|
34ae2d38c5 | ||
|
|
a1c95544cb | ||
|
|
c6dc38c35c | ||
|
|
39203ab598 | ||
|
|
51a95a84aa | ||
|
|
8a8d45e642 | ||
|
|
52eb7dbc0c | ||
|
|
0e14b60f12 | ||
|
|
d373ab7204 | ||
|
|
4f9a563ba7 | ||
|
|
852da19b1e | ||
|
|
ddfc040a53 | ||
|
|
df3ccb763a | ||
|
|
f42561ca93 | ||
|
|
580e28519a | ||
|
|
9ecc1d8f19 | ||
|
|
40629ed7b9 | ||
|
|
5790135add | ||
|
|
fd862ed6c6 | ||
|
|
33763af96c | ||
|
|
7c05df3cfb | ||
|
|
f471e2d4c5 | ||
|
|
d4fd093521 | ||
|
|
40003c7789 | ||
|
|
b94f99f338 | ||
|
|
bd21644571 | ||
|
|
5f3599d9b8 | ||
|
|
1e4a30bd70 | ||
|
|
e7dc5de9f2 | ||
|
|
ccb9cb28f5 | ||
|
|
4d9b72c922 | ||
|
|
a51ae13a39 | ||
|
|
dfca186688 | ||
|
|
fadd229a89 | ||
|
|
7acc69adc4 | ||
|
|
d88e4120a1 | ||
|
|
ef98edd91a | ||
|
|
f4548bbe34 | ||
|
|
11a5faca1d | ||
|
|
c37b0e8cb5 | ||
|
|
a20570a6eb | ||
|
|
5e3edb7e1d | ||
|
|
ad8f1d2da6 | ||
|
|
24b23c894f | ||
|
|
c551d5fb81 | ||
|
|
fba43894c1 | ||
|
|
22cc7e086c | ||
|
|
1791008729 | ||
|
|
90e15dd253 | ||
|
|
7db73c076c | ||
|
|
95ad6e99d9 | ||
|
|
0b2a5d0f61 | ||
|
|
b7acce0814 | ||
|
|
8744e76cad | ||
|
|
446b3c13dc | ||
|
|
3951e28148 | ||
|
|
b74d679608 | ||
|
|
edbc878b73 | ||
|
|
f706209ec1 | ||
|
|
bf000b188f | ||
|
|
def1736a9b | ||
|
|
0242f4c0c3 | ||
|
|
5cd399b2df | ||
|
|
9ddb662016 | ||
|
|
2947275d54 | ||
|
|
e43f814872 | ||
|
|
6e16f52e28 | ||
|
|
fca13557df | ||
|
|
824a6df55a | ||
|
|
b98b526c50 | ||
|
|
8f6aa4f4a5 | ||
|
|
00a07a79b2 | ||
|
|
264dfbef2e | ||
|
|
2e27814809 | ||
|
|
f767f40e56 | ||
|
|
543ecc071a | ||
|
|
2a14f39495 | ||
|
|
95c8ae2334 | ||
|
|
338ea13828 | ||
|
|
4a8b9e5fec | ||
|
|
e281cac3d3 | ||
|
|
a495829a3c | ||
|
|
b0deed2a89 | ||
|
|
70a75abf74 | ||
|
|
1aa97f8e79 | ||
|
|
b4000235ac | ||
|
|
4b93f29a1c | ||
|
|
4892a50670 | ||
|
|
2fe0ac0ef9 | ||
|
|
333ae72148 | ||
|
|
5fd5b7f303 | ||
|
|
528cf45f3f | ||
|
|
c7308e7320 | ||
|
|
e2a49eaab7 | ||
|
|
44bd6f235c | ||
|
|
601d15b513 | ||
|
|
9e93485a97 | ||
|
|
ad87b2115d | ||
|
|
27a587d31f | ||
|
|
fc8fa27602 | ||
|
|
f9aebc8ee3 | ||
|
|
1167da8f4c | ||
|
|
7a5fbcdccd | ||
|
|
345e929712 | ||
|
|
358862fe59 | ||
|
|
3dde9bb293 | ||
|
|
99ae4ccadd | ||
|
|
98e9ffe0ef | ||
|
|
6927bfe8ac | ||
|
|
340a3a8fa3 | ||
|
|
4724763991 | ||
|
|
03353ad08c | ||
|
|
95c3354fcd | ||
|
|
1bda2f92b9 | ||
|
|
bd3c706934 | ||
|
|
ef3663aa36 | ||
|
|
427ff717d4 | ||
|
|
b409300412 | ||
|
|
ca1f974dbe | ||
|
|
6a8c86096b | ||
|
|
2b2fd9965b | ||
|
|
0938635eb2 | ||
|
|
a4a186751e | ||
|
|
ea5169b5c5 | ||
|
|
01bd195847 | ||
|
|
a72c26a935 | ||
|
|
a9900d9bfa | ||
|
|
6896401d2d | ||
|
|
886f01c9f3 | ||
|
|
59c9251d70 | ||
|
|
fad5f010d2 | ||
|
|
737c4a92b9 | ||
|
|
d3e8675948 | ||
|
|
a4ffc7a27c | ||
|
|
91bf7b1387 | ||
|
|
1396296337 | ||
|
|
e4672355fc | ||
|
|
129ed25ca4 | ||
|
|
e6d7e5fe98 | ||
|
|
73ce5fa11f | ||
|
|
ce01c3d4ce | ||
|
|
3b3de316ea | ||
|
|
8c739ce54d | ||
|
|
0aa4d6c967 | ||
|
|
d7a3f4d87d | ||
|
|
fe9e074581 | ||
|
|
40813e8752 | ||
|
|
e90f2e4142 | ||
|
|
2a19ea709b | ||
|
|
30c9be303f | ||
|
|
e101b79472 | ||
|
|
8ad919f952 | ||
|
|
294543c46e | ||
|
|
79f8363d47 | ||
|
|
6d3553b0b5 | ||
|
|
403ab4e281 | ||
|
|
87e7c43032 | ||
|
|
a321b41699 | ||
|
|
fea34863e3 | ||
|
|
bcaf7ab73e | ||
|
|
b9d7eaee1b | ||
|
|
d605045858 | ||
|
|
cf2ab617c2 | ||
|
|
204514cb08 | ||
|
|
cfe01cca75 | ||
|
|
ac294c58ae | ||
|
|
6950eb2f30 | ||
|
|
847f81374b | ||
|
|
bb09aea8bb | ||
|
|
2e1ff333f5 | ||
|
|
c14a2b4011 | ||
|
|
d9c6c3d2d0 | ||
|
|
91d4477ed9 | ||
|
|
623c0a127e | ||
|
|
bc64666700 | ||
|
|
5c7dd7d782 | ||
|
|
e78a2da6c0 | ||
|
|
065be6f3d7 | ||
|
|
874f3330b8 | ||
|
|
684edfa10b | ||
|
|
e69a120965 | ||
|
|
4a36244294 | ||
|
|
cb444be0f7 | ||
|
|
8b5cbf186f | ||
|
|
dbc6f8a196 | ||
|
|
9b94604166 | ||
|
|
cc98a85711 | ||
|
|
6855d06f55 | ||
|
|
89d90ddf5b | ||
|
|
6280111121 | ||
|
|
231d41c15f | ||
|
|
cfca7adc66 | ||
|
|
aedd215de4 | ||
|
|
df8e839580 | ||
|
|
300441b9f7 | ||
|
|
1a5e9022ae | ||
|
|
2a3b8f87d3 | ||
|
|
b7930f1ed7 | ||
|
|
a78c2145e6 | ||
|
|
ee20a34a70 | ||
|
|
33bd80c572 | ||
|
|
031309b105 | ||
|
|
bcbd981a9b | ||
|
|
b7ce390c33 | ||
|
|
c9d099c694 | ||
|
|
fcca0329c6 | ||
|
|
c82c0bc680 | ||
|
|
2921478a0a | ||
|
|
61a5420d48 | ||
|
|
702ab6ef6e | ||
|
|
2576e71a7d | ||
|
|
0d0bd78213 | ||
|
|
8d9fa8f9cf | ||
|
|
25eaf6e353 | ||
|
|
8afcaa0b34 | ||
|
|
1824f8150c | ||
|
|
2f89778fd6 | ||
|
|
f9d250b43c | ||
|
|
3a3c09d8aa | ||
|
|
09a0d4f9e2 | ||
|
|
3bba781183 | ||
|
|
6426f8fe91 | ||
|
|
5906594148 | ||
|
|
1b188c863c | ||
|
|
087b4cb571 | ||
|
|
c9496b6231 | ||
|
|
60d95d7628 | ||
|
|
dd9e7e77b5 | ||
|
|
50c9363876 | ||
|
|
938e357745 | ||
|
|
08ee51f8ab | ||
|
|
40ae555645 | ||
|
|
33f89264a6 | ||
|
|
e4ea20cc5f | ||
|
|
045b7db1af | ||
|
|
676c1b5d21 | ||
|
|
e4319246b8 | ||
|
|
32d8515bf4 | ||
|
|
d7e7113201 | ||
|
|
9493aa43a7 | ||
|
|
d07c55b831 | ||
|
|
47dab88d72 | ||
|
|
9e553aeff6 | ||
|
|
ed8e754557 | ||
|
|
651dc3df2a | ||
|
|
84e5bc3437 | ||
|
|
64fd0176ac | ||
|
|
c1f3115d4e | ||
|
|
1c70834760 | ||
|
|
7c901731bc | ||
|
|
2b2d53e515 | ||
|
|
be051ecf45 | ||
|
|
18534eb654 | ||
|
|
a5a926fd94 | ||
|
|
0cb9f2cad3 | ||
|
|
98209cc82e | ||
|
|
1879afa6a4 | ||
|
|
4a6404dfec | ||
|
|
0fa1c4a08f | ||
|
|
573d7c5776 | ||
|
|
c56c9bf260 | ||
|
|
387865789f | ||
|
|
03fcf43a89 | ||
|
|
df8090813a | ||
|
|
849b29d00f | ||
|
|
4b7f65e1c4 | ||
|
|
4545d81e50 | ||
|
|
1ac5f060a4 | ||
|
|
7e1ff8e315 | ||
|
|
4e0c1fee97 | ||
|
|
0b38f23f2d | ||
|
|
98ea6861c1 | ||
|
|
c07b628ea1 | ||
|
|
b1b979c0b5 | ||
|
|
35b708b01d | ||
|
|
229ae0d44f | ||
|
|
7d6897fa36 | ||
|
|
5851093590 | ||
|
|
4646c1d1f0 | ||
|
|
f3763dbf72 | ||
|
|
6a8c60ec78 | ||
|
|
ae437fd5d6 | ||
|
|
7251c984c8 | ||
|
|
ec449220eb | ||
|
|
78265944f0 | ||
|
|
d2791f6d1b | ||
|
|
d525d2664b | ||
|
|
a4ccea91ad | ||
|
|
750da161eb | ||
|
|
ac50312f0b | ||
|
|
8d44d48072 | ||
|
|
6c2baa1708 | ||
|
|
4525cfe594 | ||
|
|
921f96c975 | ||
|
|
29ce57d3af | ||
|
|
2ca1e6305c | ||
|
|
827b404a57 | ||
|
|
83569142c1 | ||
|
|
2da0faacc3 | ||
|
|
cf51bee2cc | ||
|
|
0dd55dc947 | ||
|
|
620fa0430c | ||
|
|
d053590257 | ||
|
|
684af3de61 | ||
|
|
6c6e26ed0b | ||
|
|
4a05bfbd08 | ||
|
|
787dc7b32f | ||
|
|
85a1f99f6e | ||
|
|
4fe8a1199e | ||
|
|
7312dbc4c5 | ||
|
|
cfecfabc92 | ||
|
|
587160c5fe | ||
|
|
ee7fe3ed33 | ||
|
|
47d4a6cc29 | ||
|
|
c1e4763369 |
@@ -19,8 +19,6 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
编译RedKale 1.8.x版本需要在源码工程中的编译器选项中加入: <b>-XDignore.symbol.file=true</b>
|
|
||||||
|
|
||||||
<h5>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
|
<h5>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
|
||||||
|
|
||||||
<h5>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
|
<h5>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 &
|
||||||
|
|
||||||
|
|||||||
@@ -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,14 +8,14 @@
|
|||||||
|
|
||||||
</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"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<response>
|
<response>
|
||||||
<defcookie domain="" path=""/>
|
<defcookie domain="" path="/"/>
|
||||||
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
||||||
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
||||||
</response>
|
</response>
|
||||||
|
|||||||
@@ -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&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>
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>
|
|
||||||
@@ -16,10 +16,6 @@
|
|||||||
<directory>${project.basedir}/conf</directory>
|
<directory>${project.basedir}/conf</directory>
|
||||||
<outputDirectory>conf</outputDirectory>
|
<outputDirectory>conf</outputDirectory>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
|
||||||
<directory>${project.basedir}/libs</directory>
|
|
||||||
<outputDirectory>libs</outputDirectory>
|
|
||||||
</fileSet>
|
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<directory>${project.basedir}/logs</directory>
|
<directory>${project.basedir}/logs</directory>
|
||||||
<outputDirectory>logs</outputDirectory>
|
<outputDirectory>logs</outputDirectory>
|
||||||
|
|||||||
@@ -63,10 +63,10 @@
|
|||||||
<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 />
|
||||||
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
|
|
||||||
</compilerArguments>
|
</compilerArguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
<version>2.6</version>
|
<version>2.6</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
|
<addMavenDescriptor>false</addMavenDescriptor>
|
||||||
<manifest>
|
<manifest>
|
||||||
<mainClass>org.redkale.boot.Application</mainClass>
|
<mainClass>org.redkale.boot.Application</mainClass>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -113,7 +114,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>2.10.3</version>
|
<version>3.0.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
|
|||||||
@@ -116,16 +116,16 @@
|
|||||||
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||||
charset: 文本编码, 默认: UTF-8
|
charset: 文本编码, 默认: UTF-8
|
||||||
backlog: 默认10K
|
backlog: 默认10K
|
||||||
threads: 线程数, 默认: CPU核数*32
|
threads: 线程数, 默认: CPU核数*2,最小8个
|
||||||
maxconns:最大连接数, 小于1表示无限制, 默认: 0
|
maxconns:最大连接数, 小于1表示无限制, 默认: 0
|
||||||
maxbody: request.body最大值, 默认: 64K
|
maxbody: request.body最大值, 默认: 64K
|
||||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 32K; (HTTP 2.0、WebSocket,必须要16k以上)
|
bufferCapacity: ByteBuffer的初始化大小, TCP默认: 32K; (HTTP 2.0、WebSocket,必须要16k以上); UDP默认: 1350B
|
||||||
bufferPoolSize: ByteBuffer池的大小,默认: 线程数*4
|
bufferPoolSize: ByteBuffer池的大小,默认: 线程数*4
|
||||||
responsePoolSize: Response池的大小,默认: 线程数*2
|
responsePoolSize: Response池的大小,默认: 线程数*2
|
||||||
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,默认值为aio;UDP情况下值也可以是bio,默认值为bio;
|
netimpl: ProtocolServer的实现类。TCP情况下值可以是aio或nio,默认值为aio;UDP情况下值可以是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="">
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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&autoReconnectForPools=true&characterEncoding=utf8 -->
|
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&autoReconnectForPools=true&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>
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
/** *****************************************************************************
|
|
||||||
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
|
|
||||||
* which accompanies this distribution.
|
|
||||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
* and the Eclipse Distribution License is available at
|
|
||||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Linda DeMichiel - Java Persistence 2.1
|
|
||||||
* Linda DeMichiel - Java Persistence 2.0
|
|
||||||
*
|
|
||||||
***************************************************************************** */
|
|
||||||
package javax.persistence;
|
|
||||||
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import static java.lang.annotation.ElementType.FIELD;
|
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides for the specification of generation strategies for the
|
|
||||||
* values of primary keys.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The <code>GeneratedValue</code> annotation
|
|
||||||
* may be applied to a primary key property or field of an entity or
|
|
||||||
* mapped superclass in conjunction with the {@link Id} annotation.
|
|
||||||
* The use of the <code>GeneratedValue</code> annotation is only
|
|
||||||
* required to be supported for simple primary keys. Use of the
|
|
||||||
* <code>GeneratedValue</code> annotation is not supported for derived
|
|
||||||
* primary keys.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
*
|
|
||||||
* Example 1:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* public Long getId() { return id; }
|
|
||||||
*
|
|
||||||
* Example 2:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* Long id;
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see Id
|
|
||||||
*
|
|
||||||
* @since Java Persistence 1.0
|
|
||||||
*/
|
|
||||||
@Target({METHOD, FIELD})
|
|
||||||
@Retention(RUNTIME)
|
|
||||||
|
|
||||||
public @interface GeneratedValue {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see Column
|
* @see Column
|
||||||
* @see GeneratedValue
|
* see GeneratedValue
|
||||||
*
|
*
|
||||||
* @since Java Persistence 1.0
|
* @since Java Persistence 1.0
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -31,5 +30,7 @@ module org.redkale {
|
|||||||
exports org.redkale.util;
|
exports org.redkale.util;
|
||||||
exports org.redkale.watch;
|
exports org.redkale.watch;
|
||||||
|
|
||||||
|
uses org.redkale.source.SourceLoader;
|
||||||
|
uses org.redkale.util.ResourceInjectLoader;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -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().toString(), "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);
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ public final class Application {
|
|||||||
public static final String RESNAME_APP_TIME = "APP_TIME";
|
public static final String RESNAME_APP_TIME = "APP_TIME";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前进程的根目录, 类型:String、File、Path
|
* 当前进程的根目录, 类型:String、File、Path、URI
|
||||||
*/
|
*/
|
||||||
public static final String RESNAME_APP_HOME = "APP_HOME";
|
public static final String RESNAME_APP_HOME = "APP_HOME";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前进程的配置目录,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、File、Path
|
* 当前进程的配置目录,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、File、Path、URI
|
||||||
*/
|
*/
|
||||||
public static final String RESNAME_APP_CONF = "APP_CONF";
|
public static final String RESNAME_APP_CONF = "APP_CONF";
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ public final class Application {
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------
|
||||||
//是否用于main方法运行
|
//是否用于main方法运行
|
||||||
private final boolean singletonrun;
|
final boolean singletonrun;
|
||||||
|
|
||||||
//根WatchFactory
|
//根WatchFactory
|
||||||
//private final WatchFactory watchFactory = WatchFactory.root();
|
//private final WatchFactory watchFactory = WatchFactory.root();
|
||||||
@@ -143,7 +143,7 @@ public final class Application {
|
|||||||
private final File home;
|
private final File home;
|
||||||
|
|
||||||
//配置文件目录
|
//配置文件目录
|
||||||
private final File conf;
|
private final URI confPath;
|
||||||
|
|
||||||
//日志
|
//日志
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
@@ -171,22 +171,24 @@ 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);
|
||||||
this.resourceFactory.register(RESNAME_APP_HOME, Path.class, root.toPath());
|
this.resourceFactory.register(RESNAME_APP_HOME, Path.class, root.toPath());
|
||||||
this.resourceFactory.register(RESNAME_APP_HOME, File.class, root);
|
this.resourceFactory.register(RESNAME_APP_HOME, File.class, root);
|
||||||
|
this.resourceFactory.register(RESNAME_APP_HOME, URI.class, root.toURI());
|
||||||
try {
|
try {
|
||||||
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
|
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
|
||||||
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.contains("://")) {
|
||||||
this.conf = new File(confsubpath).getCanonicalFile();
|
this.confPath = new URI(confsubpath);
|
||||||
|
} else if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||||
|
this.confPath = new File(confsubpath).getCanonicalFile().toURI();
|
||||||
} else {
|
} else {
|
||||||
this.conf = new File(this.home, confsubpath).getCanonicalFile();
|
this.confPath = new File(this.home, confsubpath).getCanonicalFile().toURI();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
String localaddr = config.getValue("address", "").trim();
|
String localaddr = config.getValue("address", "").trim();
|
||||||
@@ -210,11 +212,12 @@ 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 URI logConfURI = "file".equals(confPath.getScheme()) ? new File(new File(confPath), "logging.properties").toURI()
|
||||||
if (logconf.isFile() && logconf.canRead()) {
|
: URI.create(confPath.toString() + (confPath.toString().endsWith("/") ? "" : "/") + "logging.properties");
|
||||||
|
if (!"file".equals(confPath.getScheme()) || (new File(logConfURI).isFile() && new File(logConfURI).canRead())) {
|
||||||
try {
|
try {
|
||||||
final String rootpath = root.getCanonicalPath().replace('\\', '/');
|
final String rootpath = root.getCanonicalPath().replace('\\', '/');
|
||||||
FileInputStream fin = new FileInputStream(logconf);
|
InputStream fin = logConfURI.toURL().openStream();
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.load(fin);
|
properties.load(fin);
|
||||||
fin.close();
|
fin.close();
|
||||||
@@ -302,7 +305,7 @@ public final class Application {
|
|||||||
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
|
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
|
||||||
@@ -317,7 +320,7 @@ public final class Application {
|
|||||||
transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
|
transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
@@ -376,8 +379,8 @@ public final class Application {
|
|||||||
return home;
|
return home;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getConf() {
|
public URI getConfPath() {
|
||||||
return conf;
|
return confPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getStartTime() {
|
public long getStartTime() {
|
||||||
@@ -389,7 +392,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 +402,23 @@ 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");
|
final String confpath = this.confPath.toString();
|
||||||
final String homepath = this.home.getCanonicalPath();
|
final String homepath = this.home.getCanonicalPath();
|
||||||
final String confpath = this.conf.getCanonicalPath();
|
if ("file".equals(this.confPath.getScheme())) {
|
||||||
|
File persist = new File(new File(confPath), "persistence.xml");
|
||||||
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);
|
} else {
|
||||||
|
System.setProperty(DataSources.DATASOURCE_CONFPATH, confpath + (confpath.endsWith("/") ? "" : "/") + "persistence.xml");
|
||||||
|
}
|
||||||
|
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 +433,17 @@ 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 URI df = (dfload.indexOf('/') < 0) ? URI.create(confpath + (confpath.endsWith("/") ? "" : "/") + dfload) : new File(dfload).toURI();
|
||||||
if (df.isFile()) {
|
if (!"file".equals(df.getScheme()) || new File(df).isFile()) {
|
||||||
Properties ps = new Properties();
|
Properties ps = new Properties();
|
||||||
InputStream in = new FileInputStream(df);
|
try {
|
||||||
|
InputStream in = df.toURL().openStream();
|
||||||
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)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "load properties(" + dfload + ") error", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,6 +451,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 +479,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);
|
||||||
@@ -551,9 +570,10 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void restoreConfig() throws IOException {
|
public void restoreConfig() throws IOException {
|
||||||
|
if (!"file".equals(this.confPath.getScheme())) return;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
File confFile = new File(this.conf, "application.xml");
|
File confFile = new File(this.confPath.toString(), "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.toString(), "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();
|
||||||
@@ -564,7 +584,7 @@ public final class Application {
|
|||||||
final Application application = this;
|
final Application application = this;
|
||||||
new Thread() {
|
new Thread() {
|
||||||
{
|
{
|
||||||
setName("Application-Control-Thread");
|
setName("Redkale-Application-SelfServer-Thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -735,7 +755,7 @@ public final class Application {
|
|||||||
Thread thread = new Thread() {
|
Thread thread = new Thread() {
|
||||||
{
|
{
|
||||||
String host = serconf.getValue("host", "0.0.0.0").replace("0.0.0.0", "*");
|
String host = serconf.getValue("host", "0.0.0.0").replace("0.0.0.0", "*");
|
||||||
setName(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
|
setName("Redkale-" + serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
|
||||||
this.setDaemon(true);
|
this.setDaemon(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,13 +825,22 @@ public final class Application {
|
|||||||
sercdl.await();
|
sercdl.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Service> T singleton(Class<T> serviceClass) throws Exception {
|
public static <T extends Service> T singleton(Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
|
||||||
return singleton("", serviceClass);
|
return singleton("", serviceClass, extServiceClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Service> T singleton(String name, Class<T> serviceClass) throws Exception {
|
public static <T extends Service> T singleton(String name, Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
|
||||||
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
|
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
|
||||||
final Application application = Application.create(true);
|
final Application application = Application.create(true);
|
||||||
|
System.setProperty("red" + "kale-singleton-serviceclass", serviceClass.getName());
|
||||||
|
if (extServiceClasses != null && extServiceClasses.length > 0) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Class clazz : extServiceClasses) {
|
||||||
|
if (sb.length() > 0) sb.append(',');
|
||||||
|
sb.append(clazz.getName());
|
||||||
|
}
|
||||||
|
System.setProperty("red" + "kale-singleton-extserviceclasses", sb.toString());
|
||||||
|
}
|
||||||
application.init();
|
application.init();
|
||||||
application.start();
|
application.start();
|
||||||
for (NodeServer server : application.servers) {
|
for (NodeServer server : application.servers) {
|
||||||
@@ -827,18 +856,20 @@ public final class Application {
|
|||||||
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
|
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
|
||||||
System.setProperty(RESNAME_APP_HOME, home);
|
System.setProperty(RESNAME_APP_HOME, home);
|
||||||
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
||||||
File appfile;
|
URI appconf;
|
||||||
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
if (confsubpath.contains("://")) {
|
||||||
appfile = new File(confsubpath).getCanonicalFile();
|
appconf = URI.create(confsubpath + (confsubpath.endsWith("/") ? "" : "/") + "application.xml");
|
||||||
|
} else if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||||
|
appconf = new File(confsubpath, "application.xml").toURI();
|
||||||
} else {
|
} else {
|
||||||
appfile = new File(new File(home), confsubpath);
|
appconf = new File(new File(home, confsubpath), "application.xml").toURI();
|
||||||
}
|
}
|
||||||
File appconf = new File(appfile, "application.xml");
|
return new Application(singleton, load(appconf.toURL().openStream()));
|
||||||
return new Application(singleton, load(new FileInputStream(appconf)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Utility.midnight(); //先初始化一下Utility
|
Utility.midnight(); //先初始化一下Utility
|
||||||
|
Thread.currentThread().setName("Redkale-Application-Main-Thread");
|
||||||
//运行主程序
|
//运行主程序
|
||||||
final Application application = Application.create(false);
|
final Application application = Application.create(false);
|
||||||
if (System.getProperty("CMD") != null) {
|
if (System.getProperty("CMD") != null) {
|
||||||
@@ -871,7 +902,7 @@ public final class Application {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdown() throws Exception {
|
public void shutdown() throws Exception {
|
||||||
for (ApplicationListener listener : this.listeners) {
|
for (ApplicationListener listener : this.listeners) {
|
||||||
try {
|
try {
|
||||||
listener.preShutdown(this);
|
listener.preShutdown(this);
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ 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.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.jar.*;
|
import java.util.jar.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import java.util.regex.*;
|
import java.util.regex.*;
|
||||||
@@ -30,12 +31,14 @@ 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<>(); //符合条件的结果
|
||||||
|
|
||||||
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
||||||
|
|
||||||
|
private Predicate<String> expectPredicate;
|
||||||
|
|
||||||
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
||||||
|
|
||||||
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
||||||
@@ -136,10 +139,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 +154,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 +181,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;
|
||||||
@@ -183,15 +199,16 @@ public final class ClassFilter<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
||||||
if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)的
|
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)的
|
||||||
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
||||||
} else {
|
} else {
|
||||||
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
||||||
}
|
}
|
||||||
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,6 +350,14 @@ public final class ClassFilter<T> {
|
|||||||
this.refused = refused;
|
this.refused = refused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Predicate<String> getExpectPredicate() {
|
||||||
|
return expectPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectPredicate(Predicate<String> predicate) {
|
||||||
|
this.expectPredicate = predicate;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getPrivilegeIncludes() {
|
public Set<String> getPrivilegeIncludes() {
|
||||||
return privilegeIncludes;
|
return privilegeIncludes;
|
||||||
}
|
}
|
||||||
@@ -347,6 +372,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 +528,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 +537,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 +556,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public class LogFileHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void open() {
|
private void open() {
|
||||||
final String name = "Logging-" + getClass().getSimpleName() + "-Thread";
|
final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread";
|
||||||
new Thread() {
|
new Thread() {
|
||||||
{
|
{
|
||||||
setName(name);
|
setName(name);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -191,7 +192,7 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
int max = 0;
|
int max = 0;
|
||||||
if (ss != null && sb != null) {
|
if (ss != null && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
if (as.getKey().length() > max) max = as.getKey().length();
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
}
|
}
|
||||||
@@ -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,7 +245,9 @@ 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());
|
||||||
|
super.interceptorServices.stream().parallel().forEach((service) -> {
|
||||||
|
try {
|
||||||
final Class stype = Sncp.getServiceType(service);
|
final Class stype = Sncp.getServiceType(service);
|
||||||
final String name = Sncp.getResourceName(service);
|
final String name = Sncp.getResourceName(service);
|
||||||
RestService rs = (RestService) stype.getAnnotation(RestService.class);
|
RestService rs = (RestService) stype.getAnnotation(RestService.class);
|
||||||
@@ -252,26 +256,34 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
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;
|
||||||
|
synchronized (restedObjects) {
|
||||||
if (restedObjects.contains(service)) {
|
if (restedObjects.contains(service)) {
|
||||||
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
|
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
restedObjects.add(service); //避免重复创建Rest对象
|
restedObjects.add(service); //避免重复创建Rest对象
|
||||||
|
}
|
||||||
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
|
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
|
||||||
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
|
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
|
||||||
String prefix2 = prefix;
|
String prefix2 = prefix;
|
||||||
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
if (ws != null && !ws.repair()) prefix2 = "";
|
if (ws != null && !ws.repair()) prefix2 = "";
|
||||||
resourceFactory.inject(servlet, NodeHttpServer.this);
|
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||||
if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
|
//if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
|
||||||
if (ss != null) {
|
if (ss != null) {
|
||||||
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||||
for (int i = 0; i < mappings.length; i++) {
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
mappings[i] = prefix2 + mappings[i];
|
mappings[i] = prefix2 + mappings[i];
|
||||||
}
|
}
|
||||||
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
|
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<>();
|
||||||
@@ -328,7 +340,7 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
//输出信息
|
//输出信息
|
||||||
if (ss != null && !ss.isEmpty() && sb != null) {
|
if (ss != null && !ss.isEmpty() && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
int max = 0;
|
int max = 0;
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
if (as.getKey().length() > max) max = as.getKey().length();
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.lang.reflect.*;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.AbstractMap.SimpleEntry;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
@@ -153,6 +154,20 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
||||||
|
if (application.singletonrun) { //singleton模式下只加载指定的Service
|
||||||
|
final String ssc = System.getProperty("red" + "kale-singleton-serviceclass");
|
||||||
|
final String extssc = System.getProperty("red" + "kale-singleton-extserviceclasses");
|
||||||
|
if (ssc != null) {
|
||||||
|
final List<String> sscList = new ArrayList<>();
|
||||||
|
sscList.add(ssc);
|
||||||
|
if (extssc != null && !extssc.isEmpty()) {
|
||||||
|
for (String s : extssc.split(",")) {
|
||||||
|
if (!s.isEmpty()) sscList.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serviceFilter.setExpectPredicate(c -> !sscList.contains(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
||||||
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
||||||
ClassFilter otherFilter = createOtherClassFilter();
|
ClassFilter otherFilter = createOtherClassFilter();
|
||||||
@@ -161,9 +176,10 @@ public abstract class NodeServer {
|
|||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
||||||
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
||||||
|
if (!application.singletonrun) { //非singleton模式下才加载Filter、Servlet
|
||||||
loadFilter(filterFilter, otherFilter);
|
loadFilter(filterFilter, otherFilter);
|
||||||
loadServlet(servletFilter, otherFilter);
|
loadServlet(servletFilter, otherFilter);
|
||||||
|
}
|
||||||
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,19 +193,27 @@ public abstract class NodeServer {
|
|||||||
final ResourceFactory appResFactory = application.getResourceFactory();
|
final ResourceFactory appResFactory = application.getResourceFactory();
|
||||||
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
|
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
|
||||||
final AnyValue resources = application.config.getAnyValue("resources");
|
final AnyValue resources = application.config.getAnyValue("resources");
|
||||||
final Map<String, AnyValue> cacheResource = new HashMap<>();
|
final Map<String, SimpleEntry<Class, AnyValue>> cacheResource = new HashMap<>();
|
||||||
final Map<String, AnyValue> dataResources = new HashMap<>();
|
final Map<String, SimpleEntry<Class, AnyValue>> dataResources = new HashMap<>();
|
||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
||||||
try {
|
try {
|
||||||
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
||||||
if (type == DataSource.class) type = DataJdbcSource.class;
|
if (type == DataSource.class) {
|
||||||
|
type = DataMemorySource.class;
|
||||||
|
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
|
||||||
|
if (itemConf.getValue("name", "").contains(DataSources.JDBC_URL)) {
|
||||||
|
type = DataJdbcSource.class;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!Service.class.isAssignableFrom(type)) {
|
if (!Service.class.isAssignableFrom(type)) {
|
||||||
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
|
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
|
||||||
} else if (CacheSource.class.isAssignableFrom(type)) {
|
} else if (CacheSource.class.isAssignableFrom(type)) {
|
||||||
cacheResource.put(sourceConf.getValue("name", ""), sourceConf);
|
cacheResource.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
|
||||||
} else if (DataSource.class.isAssignableFrom(type)) {
|
} else if (DataSource.class.isAssignableFrom(type)) {
|
||||||
dataResources.put(sourceConf.getValue("name", ""), sourceConf);
|
dataResources.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
|
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
|
||||||
}
|
}
|
||||||
@@ -226,11 +250,15 @@ 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();
|
||||||
|
if (sourceType == DataJdbcSource.class) {
|
||||||
|
source = DataSources.createDataSource(resourceName, sourceConf);
|
||||||
|
} else {
|
||||||
boolean can = false;
|
boolean can = false;
|
||||||
for (Constructor cr : sourceType.getConstructors()) {
|
for (Constructor cr : sourceType.getConstructors()) {
|
||||||
if (cr.getParameterCount() == 0) {
|
if (cr.getParameterCount() == 0) {
|
||||||
@@ -248,6 +276,7 @@ public abstract class NodeServer {
|
|||||||
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
source = DataSources.createDataSource(resourceName); //从persistence.xml配置中创建
|
source = DataSources.createDataSource(resourceName); //从persistence.xml配置中创建
|
||||||
needinit = false;
|
needinit = false;
|
||||||
@@ -284,6 +313,7 @@ public abstract class NodeServer {
|
|||||||
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
|
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
|
||||||
try {
|
try {
|
||||||
if (field.getAnnotation(Resource.class) == null) return;
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if (!(src instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + src);
|
||||||
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
|
||||||
final Service srcService = (Service) src;
|
final Service srcService = (Service) src;
|
||||||
SncpClient client = Sncp.getSncpClient(srcService);
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
@@ -292,8 +322,12 @@ public abstract class NodeServer {
|
|||||||
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
||||||
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
||||||
|
|
||||||
AnyValue sourceConf = cacheResource.get(resourceName);
|
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName);
|
||||||
if (sourceConf == null) sourceConf = dataResources.get(resourceName);
|
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
|
||||||
|
if (sourceConf == null) {
|
||||||
|
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
|
||||||
|
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
|
||||||
|
}
|
||||||
final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
|
final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
|
||||||
Object source = null;
|
Object source = null;
|
||||||
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
||||||
@@ -370,6 +404,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 +436,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
|
||||||
|
if (!serviceImplClass.getName().startsWith("org.redkale.")) 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 +448,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);
|
||||||
@@ -460,7 +498,7 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
//----------------- init -----------------
|
//----------------- init -----------------
|
||||||
List<Service> swlist = new ArrayList<>(localServices);
|
List<Service> swlist = new ArrayList<>(localServices);
|
||||||
Collections.sort(swlist, (o1, o2) -> {
|
swlist.sort((o1, o2) -> {
|
||||||
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
||||||
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
||||||
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
@@ -473,24 +511,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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
private NodeSncpServer(Application application, AnyValue serconf) {
|
private NodeSncpServer(Application application, AnyValue serconf) {
|
||||||
super(application, createServer(application, serconf));
|
super(application, createServer(application, serconf));
|
||||||
this.sncpServer = (SncpServer) this.server;
|
this.sncpServer = (SncpServer) this.server;
|
||||||
this.consumer = sncpServer == null ? null : x -> sncpServer.addSncpServlet(x);
|
this.consumer = sncpServer == null || application.singletonrun ? null : x -> sncpServer.addSncpServlet(x); //singleton模式下不生成SncpServlet
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class FilterWatchService extends AbstractWatchService {
|
|||||||
@Resource
|
@Resource
|
||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
|
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
|
||||||
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
|
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
|
||||||
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
||||||
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
|
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
|
||||||
|
|||||||
@@ -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<>();
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
@RestConvert(type = void.class)
|
@RestConvert(type = void.class)
|
||||||
@RestMapping(name = "setfield", auth = false, comment = "设置Service中指定字段的内容")
|
@RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容")
|
||||||
public RetResult setfield(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult setField(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
@RestParam(name = "field", comment = "字段名") String field,
|
@RestParam(name = "field", comment = "字段名") String field,
|
||||||
@RestParam(name = "value", comment = "字段值") String value) {
|
@RestParam(name = "value", comment = "字段值") String value) {
|
||||||
@@ -65,8 +65,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RestConvert(type = void.class)
|
@RestConvert(type = void.class)
|
||||||
@RestMapping(name = "getfield", auth = false, comment = "查询Service中指定字段的内容")
|
@RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容")
|
||||||
public RetResult getfield(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult getField(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
@RestParam(name = "field", comment = "字段名") String field) {
|
@RestParam(name = "field", comment = "字段名") String field) {
|
||||||
if (name == null) name = "";
|
if (name == null) name = "";
|
||||||
@@ -98,8 +98,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RestConvert(type = void.class)
|
@RestConvert(type = void.class)
|
||||||
@RestMapping(name = "runmethod", auth = false, comment = "调用Service中指定方法")
|
@RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法")
|
||||||
public RetResult runmethod(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult runMethod(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
@RestParam(name = "method", comment = "Service的方法名") String method,
|
@RestParam(name = "method", comment = "Service的方法名") String method,
|
||||||
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
|
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
|
||||||
@@ -169,26 +169,30 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "load", auth = false, comment = "动态增加Service")
|
@RestMapping(name = "loadService", 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 = "reloadService", 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 = "stopService", 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 = "findService", 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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ public class ServletWatchService extends AbstractWatchService {
|
|||||||
@Resource
|
@Resource
|
||||||
protected TransportFactory transportFactory;
|
protected TransportFactory transportFactory;
|
||||||
//
|
//
|
||||||
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
|
// @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet")
|
||||||
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
// //待开发
|
// //待开发
|
||||||
// return RetResult.success();
|
// return RetResult.success();
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// @RestMapping(name = "stop", auth = false, comment = "动态停止Servlet")
|
// @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet")
|
||||||
// public RetResult stopServlet(String type) {
|
// public RetResult stopServlet(String type) {
|
||||||
// //待开发
|
// //待开发
|
||||||
// return RetResult.success();
|
// return RetResult.success();
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot.watch;
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Properties;
|
import java.util.*;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import org.redkale.boot.Application;
|
import org.redkale.boot.Application;
|
||||||
import org.redkale.net.http.*;
|
import org.redkale.net.http.*;
|
||||||
@@ -16,6 +16,7 @@ import org.redkale.source.*;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* WATCH服务, 操作DataSource源
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@@ -31,13 +32,25 @@ public class SourceWatchService extends AbstractWatchService {
|
|||||||
@Comment("PoolSource调用change方法失败")
|
@Comment("PoolSource调用change方法失败")
|
||||||
public static final int RET_SOURCE_METHOD_INVOKE_NOT_EXISTS = 1605_0003;
|
public static final int RET_SOURCE_METHOD_INVOKE_NOT_EXISTS = 1605_0003;
|
||||||
|
|
||||||
|
@Resource(name = "APP_HOME")
|
||||||
|
protected File home;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
@RestMapping(name = "change", auth = false, comment = "动态更改DataSource的配置")
|
@RestMapping(name = "change", auth = false, comment = "动态更改DataSource的配置")
|
||||||
public RetResult addNode(@RestParam(name = "name", comment = "DataSource的标识") final String name,
|
public RetResult addNode(@RestParam(name = "name", comment = "DataSource的标识") final String name,
|
||||||
@RestParam(name = "properties", comment = "配置") final Properties properties) throws IOException {
|
@RestParam(name = "properties", comment = "配置") Properties properties,
|
||||||
|
@RestParam(name = "xmlpath", comment = "配置文件路径") String xmlpath) throws IOException {
|
||||||
if (name == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (name)");
|
if (name == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (name)");
|
||||||
|
if (properties == null && xmlpath != null) {
|
||||||
|
File f = new File(xmlpath);
|
||||||
|
if (!f.isFile()) f = new File(home, xmlpath);
|
||||||
|
if (!f.isFile()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found file (" + xmlpath + ")");
|
||||||
|
FileInputStream in = new FileInputStream(f);
|
||||||
|
Map<String, Properties> map = DataSources.loadPersistenceXml(in);
|
||||||
|
properties = map.get(name);
|
||||||
|
}
|
||||||
if (properties == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (properties)");
|
if (properties == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (properties)");
|
||||||
DataSource source = null;
|
DataSource source = null;
|
||||||
for (DataSource s : application.getDataSources()) {
|
for (DataSource s : application.getDataSources()) {
|
||||||
@@ -76,4 +89,34 @@ public class SourceWatchService extends AbstractWatchService {
|
|||||||
return new RetResult(RET_SOURCE_METHOD_INVOKE_NOT_EXISTS, "poolsource invoke method('change') error");
|
return new RetResult(RET_SOURCE_METHOD_INVOKE_NOT_EXISTS, "poolsource invoke method('change') error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test1", auth = false, comment = "预留")
|
||||||
|
public RetResult test1() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test2", auth = false, comment = "预留")
|
||||||
|
public RetResult test2() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test3", auth = false, comment = "预留")
|
||||||
|
public RetResult test3() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test4", auth = false, comment = "预留")
|
||||||
|
public RetResult test4() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test5", auth = false, comment = "预留")
|
||||||
|
public RetResult test5() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test6", auth = false, comment = "预留")
|
||||||
|
public RetResult test6() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/org/redkale/convert/AnyDecoder.java
Normal file
64
src/org/redkale/convert/AnyDecoder.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.convert.Reader.ValueType;
|
||||||
|
import static org.redkale.convert.Reader.ValueType.MAP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对不明类型的对象进行反序列化。 <br>
|
||||||
|
* <b>注意: 目前只支持文本格式</b> <br>
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class AnyDecoder implements Decodeable<Reader, Object> {
|
||||||
|
|
||||||
|
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
|
||||||
|
|
||||||
|
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
|
||||||
|
|
||||||
|
protected final Decodeable<Reader, String> stringDecoder;
|
||||||
|
|
||||||
|
protected final CollectionDecoder collectionDecoder;
|
||||||
|
|
||||||
|
protected final MapDecoder mapDecoder;
|
||||||
|
|
||||||
|
public AnyDecoder(final ConvertFactory factory) {
|
||||||
|
this.stringDecoder = factory.loadDecoder(String.class);
|
||||||
|
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
|
||||||
|
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertFrom(Reader in) {
|
||||||
|
ValueType vt = in.readType();
|
||||||
|
if (vt == null) return null;
|
||||||
|
switch (vt) {
|
||||||
|
case ARRAY:
|
||||||
|
return this.collectionDecoder.convertFrom(in);
|
||||||
|
case MAP:
|
||||||
|
return this.mapDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
return this.stringDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return void.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -28,9 +28,9 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
|
|
||||||
protected final Class componentClass;
|
protected final Class componentClass;
|
||||||
|
|
||||||
protected final Decodeable<Reader, T> decoder;
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
this.componentClass = (Class) this.componentType;
|
this.componentClass = (Class) this.componentType;
|
||||||
}
|
}
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@@ -66,14 +66,15 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public T[] convertFrom(Reader in, DeMember member) {
|
public T[] convertFrom(Reader in, DeMember member) {
|
||||||
int len = in.readArrayB(member, decoder);
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
contentLength = in.readMemberContentLength(member, decoder);
|
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||||
len = Reader.SIGN_NOLENGTH;
|
len = Reader.SIGN_NOLENGTH;
|
||||||
}
|
}
|
||||||
if (this.decoder == null) {
|
if (this.componentDecoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -84,7 +85,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Decodeable<Reader, T> localdecoder = this.decoder;
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
final List<T> result = new ArrayList();
|
final List<T> result = new ArrayList();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
@@ -92,7 +93,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader itemReader = getItemReader(in, member, first);
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
if (itemReader == null) break;
|
if (itemReader == null) break;
|
||||||
result.add(readMemberValue(itemReader, member, first));
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -109,17 +110,21 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T readMemberValue(Reader in, DeMember member, boolean first) {
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
return this.decoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
|
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,8 +136,8 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decodeable<Reader, T> getDecoder() {
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
return decoder;
|
return componentDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
|
|
||||||
protected final Encodeable anyEncoder;
|
protected final Encodeable anyEncoder;
|
||||||
|
|
||||||
protected final Encodeable<Writer, Object> encoder;
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
throw new ConvertException("(" + type + ") is not a array type");
|
throw new ConvertException("(" + type + ") is not a array type");
|
||||||
}
|
}
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.encoder = factory.loadEncoder(this.componentType);
|
this.componentEncoder = factory.loadEncoder(this.componentType);
|
||||||
this.anyEncoder = factory.getAnyEncoder();
|
this.anyEncoder = factory.getAnyEncoder();
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -66,11 +66,11 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (value.length == 0) {
|
if (value.length == 0) {
|
||||||
out.writeArrayB(0, encoder, value);
|
out.writeArrayB(0, componentEncoder, value);
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.encoder == null) {
|
if (this.componentEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -81,12 +81,12 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeArrayB(value.length, encoder, value) < 0) {
|
if (out.writeArrayB(value.length, componentEncoder, value) < 0) {
|
||||||
final Type comp = this.componentType;
|
final Type comp = this.componentType;
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Object v : value) {
|
for (Object v : value) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? encoder : anyEncoder), v, first);
|
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? componentEncoder : anyEncoder), v, first);
|
||||||
if (first) first = false;
|
if (first) first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.encoder + "}";
|
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -111,8 +111,8 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, Object> getEncoder() {
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
return encoder;
|
return componentEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package org.redkale.convert;
|
|||||||
import org.redkale.util.Creator;
|
import org.redkale.util.Creator;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection的反序列化操作类 <br>
|
* Collection的反序列化操作类 <br>
|
||||||
@@ -29,9 +29,9 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
|
|
||||||
protected Creator<Collection<T>> creator;
|
protected Creator<Collection<T>> creator;
|
||||||
|
|
||||||
protected final Decodeable<Reader, T> decoder;
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -43,12 +43,12 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
this.componentType = pt.getActualTypeArguments()[0];
|
this.componentType = pt.getActualTypeArguments()[0];
|
||||||
this.creator = factory.loadCreator((Class) pt.getRawType());
|
this.creator = factory.loadCreator((Class) pt.getRawType());
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} else if (factory.isReversible()) {
|
} else if (factory.isReversible()) {
|
||||||
this.componentType = Object.class;
|
this.componentType = Object.class;
|
||||||
this.creator = factory.loadCreator(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 + ")");
|
||||||
}
|
}
|
||||||
@@ -60,20 +60,32 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//仅供类似JsonAnyDecoder这种动态创建使用, 不得调用 factory.register
|
||||||
|
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
|
||||||
|
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
|
||||||
|
Objects.requireNonNull(componentDecoder);
|
||||||
|
this.type = type;
|
||||||
|
this.componentType = componentType;
|
||||||
|
this.creator = creator;
|
||||||
|
this.componentDecoder = componentDecoder;
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<T> convertFrom(Reader in) {
|
public Collection<T> convertFrom(Reader in) {
|
||||||
return convertFrom(in, null);
|
return convertFrom(in, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<T> convertFrom(Reader in, DeMember member) {
|
public Collection<T> convertFrom(Reader in, DeMember member) {
|
||||||
int len = in.readArrayB(member, decoder);
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
contentLength = in.readMemberContentLength(member, decoder);
|
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||||
len = Reader.SIGN_NOLENGTH;
|
len = Reader.SIGN_NOLENGTH;
|
||||||
}
|
}
|
||||||
if (this.decoder == null) {
|
if (this.componentDecoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -84,7 +96,7 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Decodeable<Reader, T> localdecoder = this.decoder;
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
final Collection<T> result = this.creator.create();
|
final Collection<T> result = this.creator.create();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
@@ -92,7 +104,7 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader itemReader = getItemReader(in, member, first);
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
if (itemReader == null) break;
|
if (itemReader == null) break;
|
||||||
result.add(readMemberValue(itemReader, member, first));
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -108,12 +120,16 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T readMemberValue(Reader in, DeMember member, boolean first) {
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
return this.decoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,8 +141,8 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decodeable<Reader, T> getDecoder() {
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
return decoder;
|
return componentDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
|
|
||||||
protected final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
protected final Encodeable<Writer, Object> encoder;
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -35,12 +35,12 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
if (t instanceof TypeVariable) {
|
if (t instanceof TypeVariable) {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.loadEncoder(t);
|
this.componentEncoder = factory.loadEncoder(t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -61,11 +61,11 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (value.isEmpty()) {
|
if (value.isEmpty()) {
|
||||||
out.writeArrayB(0, encoder, value);
|
out.writeArrayB(0, componentEncoder, value);
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.encoder == null) {
|
if (this.componentEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -76,7 +76,7 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeArrayB(value.size(), encoder, value) < 0) {
|
if (out.writeArrayB(value.size(), componentEncoder, value) < 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Object v : value) {
|
for (Object v : value) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
@@ -88,7 +88,7 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeValue(Writer out, EnMember member, Object value) {
|
protected void writeValue(Writer out, EnMember member, Object value) {
|
||||||
encoder.convertTo(out, value);
|
componentEncoder.convertTo(out, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,8 +96,11 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, Object> getEncoder() {
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
return encoder;
|
return componentEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentEncoder == null ? null : componentEncoder.getType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ package org.redkale.convert;
|
|||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.*;
|
||||||
|
import org.redkale.util.Attribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化/反序列化操作类
|
* 序列化/反序列化操作类
|
||||||
@@ -31,8 +32,24 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
|||||||
return this.factory;
|
return this.factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S configWrite(S writer) {
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||||
|
writer.objFieldFunc = objFieldFunc;
|
||||||
|
writer.objExtFunc = objExtFunc;
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
|
||||||
|
|
||||||
|
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
|
||||||
|
|
||||||
public abstract boolean isBinary();
|
public abstract boolean isBinary();
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
|
||||||
|
|
||||||
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
||||||
|
|
||||||
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
||||||
|
|||||||
@@ -89,4 +89,9 @@ public final class ConvertColumnEntry {
|
|||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -89,8 +91,11 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
|
|
||||||
this.register(Number.class, NumberSimpledCoder.instance);
|
this.register(Number.class, NumberSimpledCoder.instance);
|
||||||
this.register(String.class, StringSimpledCoder.instance);
|
this.register(String.class, StringSimpledCoder.instance);
|
||||||
|
this.register(StringWrapper.class, StringWrapperSimpledCoder.instance);
|
||||||
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
||||||
|
this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance);
|
||||||
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
||||||
|
this.register(java.time.Duration.class, DurationSimpledCoder.instance);
|
||||||
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
|
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
|
||||||
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
|
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
|
||||||
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
||||||
@@ -128,6 +133,54 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
try {
|
||||||
|
Class sqldateClass = Class.forName("java.sql.Date");
|
||||||
|
this.register(sqldateClass, new SimpledCoder<R, W, java.sql.Date>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, java.sql.Date value) {
|
||||||
|
out.writeSmallString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Date convertFrom(R in) {
|
||||||
|
String t = in.readSmallString();
|
||||||
|
return t == null ? null : java.sql.Date.valueOf(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Class sqltimeClass = Class.forName("java.sql.Time");
|
||||||
|
this.register(sqltimeClass, new SimpledCoder<R, W, java.sql.Time>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, java.sql.Time value) {
|
||||||
|
out.writeSmallString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Time convertFrom(R in) {
|
||||||
|
String t = in.readSmallString();
|
||||||
|
return t == null ? null : java.sql.Time.valueOf(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Class timestampClass = Class.forName("java.sql.Timestamp");
|
||||||
|
this.register(timestampClass, new SimpledCoder<R, W, java.sql.Timestamp>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, java.sql.Timestamp value) {
|
||||||
|
out.writeSmallString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Timestamp convertFrom(R in) {
|
||||||
|
String t = in.readSmallString();
|
||||||
|
return t == null ? null : java.sql.Timestamp.valueOf(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
} catch (Throwable t) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,15 +270,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvertColumnEntry findRef(AccessibleObject element) {
|
public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) {
|
||||||
if (element == null) return null;
|
if (element == null) return null;
|
||||||
ConvertColumnEntry en = this.columnEntrys.get(element);
|
ConvertColumnEntry en = this.columnEntrys.get(element);
|
||||||
Set<String> onlyColumns = null;
|
Set<String> onlyColumns = ignoreAlls.get(clazz);
|
||||||
if (element instanceof Method) {
|
|
||||||
onlyColumns = ignoreAlls.get(((Method) element).getDeclaringClass());
|
|
||||||
} else if (element instanceof Field) {
|
|
||||||
onlyColumns = ignoreAlls.get(((Field) element).getDeclaringClass());
|
|
||||||
}
|
|
||||||
if (en != null && onlyColumns == null) return en;
|
if (en != null && onlyColumns == null) return en;
|
||||||
final ConvertType ct = this.getConvertType();
|
final ConvertType ct = this.getConvertType();
|
||||||
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
|
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
|
||||||
@@ -252,8 +300,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
for (ConvertColumn ref : ccs) {
|
for (ConvertColumn ref : ccs) {
|
||||||
if (ref.type().contains(ct)) {
|
if (ref.type().contains(ct)) {
|
||||||
if (onlyColumns != null && fieldName != null) {
|
|
||||||
String realName = ref.name().isEmpty() ? fieldName : ref.name();
|
String realName = ref.name().isEmpty() ? fieldName : ref.name();
|
||||||
|
if (onlyColumns != null && fieldName != null) {
|
||||||
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
|
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
|
||||||
}
|
}
|
||||||
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
|
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
|
||||||
@@ -261,7 +309,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
entry.setIgnore(false);
|
entry.setIgnore(false);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
if (skipIgnores.isEmpty()) return entry;
|
if (skipIgnores.isEmpty()) {
|
||||||
|
if (onlyColumns != null && realName != null && onlyColumns.contains(realName)) entry.setIgnore(false);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
|
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -404,37 +455,59 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void registerIgnoreAll(final Class type, Collection<String> excludeColumns) {
|
||||||
|
Set<String> set = ignoreAlls.get(type);
|
||||||
|
if (set == null) {
|
||||||
|
ignoreAlls.put(type, new HashSet<>(excludeColumns));
|
||||||
|
} else {
|
||||||
|
set.addAll(new ArrayList(excludeColumns));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final void register(final Class type, boolean ignore, String... columns) {
|
public final void register(final Class type, boolean ignore, String... columns) {
|
||||||
for (String column : columns) {
|
for (String column : columns) {
|
||||||
register(type, column, new ConvertColumnEntry(column, ignore));
|
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void register(final Class type, boolean ignore, Collection<String> columns) {
|
||||||
|
for (String column : columns) {
|
||||||
|
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean register(final Class type, String column, String alias) {
|
public final boolean register(final Class type, String column, String alias) {
|
||||||
return register(type, column, new ConvertColumnEntry(alias));
|
return register(type, column, new ConvertColumnEntry(alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean register(final Class type, String column, ConvertColumnEntry entry) {
|
public final boolean register(final Class type, String column, ConvertColumnEntry entry) {
|
||||||
if (type == null || column == null || entry == null) return false;
|
if (type == null || column == null || entry == null) return false;
|
||||||
|
Field field = null;
|
||||||
try {
|
try {
|
||||||
final Field field = type.getDeclaredField(column);
|
field = type.getDeclaredField(column);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
String get = "get";
|
String get = "get";
|
||||||
if (field.getType() == boolean.class || field.getType() == Boolean.class) get = "is";
|
if (field != null && (field.getType() == boolean.class || field.getType() == Boolean.class)) get = "is";
|
||||||
char[] cols = column.toCharArray();
|
char[] cols = column.toCharArray();
|
||||||
cols[0] = Character.toUpperCase(cols[0]);
|
cols[0] = Character.toUpperCase(cols[0]);
|
||||||
String col2 = new String(cols);
|
final String bigColumn = new String(cols);
|
||||||
try {
|
try {
|
||||||
register(type.getMethod(get + col2), entry);
|
register(type.getMethod(get + bigColumn), entry);
|
||||||
|
} catch (NoSuchMethodException mex) {
|
||||||
|
if (get.length() >= 3) { //get
|
||||||
|
try {
|
||||||
|
register(type.getMethod("is" + bigColumn), entry);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
register(type.getMethod("set" + col2, field.getType()), entry);
|
register(type.getMethod("set" + bigColumn, field.getType()), entry);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
}
|
}
|
||||||
return register(field, entry);
|
return field == null ? true : register(field, entry);
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final <E> boolean register(final AccessibleObject field, final ConvertColumnEntry entry) {
|
public final <E> boolean register(final AccessibleObject field, final ConvertColumnEntry entry) {
|
||||||
@@ -495,6 +568,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;
|
||||||
@@ -579,6 +675,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
decoder = od;
|
decoder = od;
|
||||||
} else if (!clazz.getName().startsWith("java.")
|
} else if (!clazz.getName().startsWith("java.")
|
||||||
|| java.net.HttpCookie.class == clazz
|
|| java.net.HttpCookie.class == clazz
|
||||||
|
|| java.util.AbstractMap.SimpleEntry.class == clazz
|
||||||
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
||||||
Decodeable simpleCoder = null;
|
Decodeable simpleCoder = null;
|
||||||
for (final Method method : clazz.getDeclaredMethods()) {
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
@@ -662,7 +759,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
encoder = new OptionalCoder(this, type);
|
encoder = new OptionalCoder(this, type);
|
||||||
} else if (clazz == Object.class) {
|
} else if (clazz == Object.class) {
|
||||||
return (Encodeable<W, E>) this.anyEncoder;
|
return (Encodeable<W, E>) this.anyEncoder;
|
||||||
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz) {
|
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz
|
||||||
|
|| java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
|
||||||
Encodeable simpleCoder = null;
|
Encodeable simpleCoder = null;
|
||||||
for (final Method method : clazz.getDeclaredMethods()) {
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
if (!Modifier.isStatic(method.getModifiers())) continue;
|
if (!Modifier.isStatic(method.getModifiers())) continue;
|
||||||
|
|||||||
102
src/org/redkale/convert/ConvertField.java
Normal file
102
src/org/redkale/convert/ConvertField.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newConvert参数中的Function返回结果的数据类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class ConvertField implements Serializable {
|
||||||
|
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
protected Type type;
|
||||||
|
|
||||||
|
protected int position;
|
||||||
|
|
||||||
|
protected Object value;
|
||||||
|
|
||||||
|
public ConvertField() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, int position, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.position = position;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, Type type, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, Type type, int position, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.position = position;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConvertField[] ofArray(Object... items) {
|
||||||
|
int len = items.length / 2;
|
||||||
|
ConvertField[] rs = new ConvertField[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]);
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(int position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonConvert.root().convertTo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ package org.redkale.convert;
|
|||||||
import org.redkale.util.Creator;
|
import org.redkale.util.Creator;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map的反序列化操作类 <br>
|
* Map的反序列化操作类 <br>
|
||||||
@@ -35,7 +35,7 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
|
|
||||||
protected final Decodeable<Reader, V> valueDecoder;
|
protected final Decodeable<Reader, V> valueDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -74,6 +74,20 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//仅供类似JsonAnyDecoder这种动态创建使用, 不得调用 factory.register
|
||||||
|
public MapDecoder(final ConvertFactory factory, Type type, Type keyType, Type valueType,
|
||||||
|
Creator<Map<K, V>> creator, final Decodeable<Reader, K> keyDecoder, Decodeable<Reader, V> valueDecoder) {
|
||||||
|
Objects.requireNonNull(keyDecoder);
|
||||||
|
Objects.requireNonNull(valueDecoder);
|
||||||
|
this.type = type;
|
||||||
|
this.keyType = keyType;
|
||||||
|
this.valueType = valueType;
|
||||||
|
this.creator = creator;
|
||||||
|
this.keyDecoder = keyDecoder;
|
||||||
|
this.valueDecoder = valueDecoder;
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<K, V> convertFrom(Reader in) {
|
public Map<K, V> convertFrom(Reader in) {
|
||||||
return convertFrom(in, null);
|
return convertFrom(in, null);
|
||||||
@@ -91,7 +105,8 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int len = in.readMapB(member, this.keyDecoder);
|
byte[] typevals = new byte[2];
|
||||||
|
int len = in.readMapB(member, typevals, this.keyDecoder, this.valueDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
@@ -100,22 +115,24 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
final Map<K, V> result = this.creator.create();
|
final Map<K, V> result = this.creator.create();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
|
Decodeable<Reader, K> kdecoder = getKeyDecoder(this.keyDecoder, typevals);
|
||||||
|
Decodeable<Reader, V> vdecoder = getValueDecoder(this.valueDecoder, typevals);
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
int startPosition = in.position();
|
int startPosition = in.position();
|
||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader entryReader = getEntryReader(in, member, first);
|
Reader entryReader = getEntryReader(in, member, first);
|
||||||
if (entryReader == null) break;
|
if (entryReader == null) break;
|
||||||
K key = readKeyMember(entryReader, member, first);
|
K key = readKeyMember(entryReader, member, kdecoder, first);
|
||||||
entryReader.readBlank();
|
entryReader.readBlank();
|
||||||
V value = readValueMember(entryReader, member, first);
|
V value = readValueMember(entryReader, member, vdecoder, first);
|
||||||
result.put(key, value);
|
result.put(key, value);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
K key = readKeyMember(in, member, first);
|
K key = readKeyMember(in, member, kdecoder, first);
|
||||||
in.readBlank();
|
in.readBlank();
|
||||||
V value = readValueMember(in, member, first);
|
V value = readValueMember(in, member, vdecoder, first);
|
||||||
result.put(key, value);
|
result.put(key, value);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
@@ -128,16 +145,24 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, K> getKeyDecoder(Decodeable<Reader, K> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, V> getValueDecoder(Decodeable<Reader, V> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getEntryReader(Reader in, DeMember member, boolean first) {
|
protected Reader getEntryReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected K readKeyMember(Reader in, DeMember member, boolean first) {
|
protected K readKeyMember(Reader in, DeMember member, Decodeable<Reader, K> decoder, boolean first) {
|
||||||
return keyDecoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected V readValueMember(Reader in, DeMember member, boolean first) {
|
protected V readValueMember(Reader in, DeMember member, Decodeable<Reader, V> decoder, boolean first) {
|
||||||
return valueDecoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
|
|
||||||
protected final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
protected final Encodeable<Writer, K> keyencoder;
|
protected final Encodeable<Writer, K> keyEncoder;
|
||||||
|
|
||||||
protected final Encodeable<Writer, V> valencoder;
|
protected final Encodeable<Writer, V> valueEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -37,11 +37,11 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
try {
|
try {
|
||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
|
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
|
||||||
this.keyencoder = factory.loadEncoder(pt[0]);
|
this.keyEncoder = factory.loadEncoder(pt[0]);
|
||||||
this.valencoder = factory.loadEncoder(pt[1]);
|
this.valueEncoder = factory.loadEncoder(pt[1]);
|
||||||
} else {
|
} else {
|
||||||
this.keyencoder = factory.getAnyEncoder();
|
this.keyEncoder = factory.getAnyEncoder();
|
||||||
this.valencoder = factory.getAnyEncoder();
|
this.valueEncoder = factory.getAnyEncoder();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -63,7 +63,7 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.keyencoder == null || this.valencoder == null) {
|
if (this.keyEncoder == null || this.valueEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -74,21 +74,21 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeMapB(values.size(), (Encodeable) keyencoder, (Encodeable) valencoder, value) < 0) {
|
if (out.writeMapB(values.size(), (Encodeable) keyEncoder, (Encodeable) valueEncoder, value) < 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Map.Entry<K, V> en : values.entrySet()) {
|
for (Map.Entry<K, V> en : values.entrySet()) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
writeMemberValue(out, member, en.getKey(), en.getValue(),first);
|
writeMemberValue(out, member, en.getKey(), en.getValue(), first);
|
||||||
if (first) first = false;
|
if (first) first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.writeMapE();
|
out.writeMapE();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeMemberValue(Writer out, EnMember member, K key, V value,boolean first) {
|
protected void writeMemberValue(Writer out, EnMember member, K key, V value, boolean first) {
|
||||||
keyencoder.convertTo(out, key);
|
keyEncoder.convertTo(out, key);
|
||||||
out.writeMapMark();
|
out.writeMapMark();
|
||||||
valencoder.convertTo(out, value);
|
valueEncoder.convertTo(out, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,12 +96,20 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, K> getKeyencoder() {
|
public Type getKeyType() {
|
||||||
return keyencoder;
|
return keyEncoder == null ? null : keyEncoder.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, V> getValencoder() {
|
public Type getValueType() {
|
||||||
return valencoder;
|
return valueEncoder == null ? null : valueEncoder.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Encodeable<Writer, K> getKeyEncoder() {
|
||||||
|
return keyEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Encodeable<Writer, V> getValueEncoder() {
|
||||||
|
return valueEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
|
|
||||||
protected ConvertFactory factory;
|
protected ConvertFactory factory;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -61,7 +61,10 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
public void init(final ConvertFactory factory) {
|
public void init(final ConvertFactory factory) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
try {
|
try {
|
||||||
if (type == Object.class) return;
|
if (type == Object.class) {
|
||||||
|
this.creatorConstructorMembers = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Class clazz = null;
|
Class clazz = null;
|
||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
@@ -91,10 +94,14 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
for (final Field field : clazz.getFields()) {
|
for (final Field field : clazz.getFields()) {
|
||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
if (factory.isConvertDisabled(field)) continue;
|
if (factory.isConvertDisabled(field)) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(clazz, field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
|
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
||||||
|
if (fieldCoder == null) {
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
||||||
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t));
|
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);
|
||||||
}
|
}
|
||||||
@@ -116,10 +123,15 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(clazz, method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
|
|
||||||
|
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
||||||
|
if (fieldCoder == null) {
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
|
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));
|
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]);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
|
|
||||||
protected ConvertFactory factory;
|
protected ConvertFactory factory;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -75,10 +75,14 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
for (final Field field : clazz.getFields()) {
|
for (final Field field : clazz.getFields()) {
|
||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
if (factory.isConvertDisabled(field)) continue;
|
if (factory.isConvertDisabled(field)) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(clazz, field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
|
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
||||||
|
if (fieldCoder == null) {
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
||||||
EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t));
|
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);
|
||||||
}
|
}
|
||||||
@@ -100,10 +104,14 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(clazz, method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
|
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
||||||
|
if (fieldCoder == null) {
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
|
||||||
EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t));
|
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);
|
||||||
}
|
}
|
||||||
@@ -156,9 +164,22 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (out.writeObjectB(value) < 0) {
|
if (out.writeObjectB(value) < 0) {
|
||||||
|
int maxPosition = 0;
|
||||||
for (EnMember member : members) {
|
for (EnMember member : members) {
|
||||||
|
maxPosition = member.getPosition();
|
||||||
out.writeObjectField(member, value);
|
out.writeObjectField(member, value);
|
||||||
}
|
}
|
||||||
|
if (out.objExtFunc != null) {
|
||||||
|
ConvertField[] extFields = out.objExtFunc.apply(value);
|
||||||
|
if (extFields != null) {
|
||||||
|
Encodeable<W, ?> anyEncoder = factory.getAnyEncoder();
|
||||||
|
for (ConvertField en : extFields) {
|
||||||
|
if (en == null) continue;
|
||||||
|
maxPosition++;
|
||||||
|
out.writeObjectField(en.getName(), en.getType(), Math.max(en.getPosition(), maxPosition), anyEncoder, en.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.writeObjectE(value);
|
out.writeObjectE(value);
|
||||||
}
|
}
|
||||||
@@ -245,24 +266,24 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
|
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
|
||||||
String fieldalias;
|
String fieldalias;
|
||||||
if (field != null) { // public field
|
if (field != null) { // public field
|
||||||
ConvertColumnEntry ref = factory.findRef(field);
|
ConvertColumnEntry ref = factory.findRef(clazz, field);
|
||||||
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
|
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
|
||||||
} else if (getter != null) {
|
} else if (getter != null) {
|
||||||
ConvertColumnEntry ref = factory.findRef(getter);
|
ConvertColumnEntry ref = factory.findRef(clazz, getter);
|
||||||
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
|
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
try {
|
try {
|
||||||
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
|
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
||||||
} else { // setter != null
|
} else { // setter != null
|
||||||
ConvertColumnEntry ref = factory.findRef(setter);
|
ConvertColumnEntry ref = factory.findRef(clazz, setter);
|
||||||
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
|
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
try {
|
try {
|
||||||
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
|
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class OptionalCoder<R extends Reader, W extends Writer, T> extends Simple
|
|||||||
|
|
||||||
protected final Encodeable<Writer, T> encoder;
|
protected final Encodeable<Writer, T> encoder;
|
||||||
|
|
||||||
private boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ package org.redkale.convert;
|
|||||||
*/
|
*/
|
||||||
public abstract class Reader {
|
public abstract class Reader {
|
||||||
|
|
||||||
|
public static enum ValueType {
|
||||||
|
STRING, ARRAY, MAP;
|
||||||
|
}
|
||||||
|
|
||||||
//当前对象字段名的游标
|
//当前对象字段名的游标
|
||||||
protected int fieldIndex;
|
protected int fieldIndex;
|
||||||
|
|
||||||
@@ -73,6 +77,13 @@ public abstract class Reader {
|
|||||||
*/
|
*/
|
||||||
public abstract void readBlank();
|
public abstract void readBlank();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取下个值的类型
|
||||||
|
*
|
||||||
|
* @return ValueType
|
||||||
|
*/
|
||||||
|
public abstract ValueType readType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
||||||
*
|
*
|
||||||
@@ -96,11 +107,12 @@ 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取数组的尾端
|
* 读取数组的尾端
|
||||||
@@ -112,11 +124,13 @@ public abstract class Reader {
|
|||||||
* 读取map的开头并返回map的size
|
* 读取map的开头并返回map的size
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
* @param keydecoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param keyDecoder Decodeable
|
||||||
|
* @param valueDecoder Decodeable
|
||||||
*
|
*
|
||||||
* @return 返回map的size
|
* @return 返回map的size
|
||||||
*/
|
*/
|
||||||
public abstract int readMapB(DeMember member, Decodeable keydecoder);
|
public abstract int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取数组的尾端
|
* 读取数组的尾端
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
|
|
||||||
protected Creator<Stream<T>> creator;
|
protected Creator<Stream<T>> creator;
|
||||||
|
|
||||||
protected final Decodeable<Reader, T> decoder;
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
this.componentType = pt.getActualTypeArguments()[0];
|
this.componentType = pt.getActualTypeArguments()[0];
|
||||||
this.creator = factory.loadCreator((Class) pt.getRawType());
|
this.creator = factory.loadCreator((Class) pt.getRawType());
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} else {
|
} else {
|
||||||
throw new ConvertException("StreamDecoder not support the type (" + type + ")");
|
throw new ConvertException("StreamDecoder not support the type (" + type + ")");
|
||||||
}
|
}
|
||||||
@@ -62,14 +62,15 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Stream<T> convertFrom(Reader in, DeMember member) {
|
public Stream<T> convertFrom(Reader in, DeMember member) {
|
||||||
int len = in.readArrayB(member, this.decoder);
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, this.componentDecoder);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
contentLength = in.readMemberContentLength(member, this.decoder);
|
contentLength = in.readMemberContentLength(member, this.componentDecoder);
|
||||||
len = Reader.SIGN_NOLENGTH;
|
len = Reader.SIGN_NOLENGTH;
|
||||||
}
|
}
|
||||||
if (this.decoder == null) {
|
if (this.componentDecoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -80,7 +81,7 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Decodeable<Reader, T> localdecoder = this.decoder;
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
final List<T> result = new ArrayList();
|
final List<T> result = new ArrayList();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
@@ -88,7 +89,7 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
Reader itemReader = getItemReader(in, member, first);
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
if (itemReader == null) break;
|
if (itemReader == null) break;
|
||||||
result.add(readMemberValue(itemReader, member, first));
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -104,12 +105,16 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
return in.hasNext(startPosition, contentLength);
|
return in.hasNext(startPosition, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T readMemberValue(Reader in, DeMember member, boolean first) {
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
return this.decoder.convertFrom(in);
|
return decoder.convertFrom(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -121,8 +126,8 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
|||||||
return componentType;
|
return componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decodeable<Reader, T> getDecoder() {
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
return decoder;
|
return componentDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
|
|
||||||
protected final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
protected final Encodeable<Writer, Object> encoder;
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
protected boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
@@ -35,12 +35,12 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
if (t instanceof TypeVariable) {
|
if (t instanceof TypeVariable) {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.loadEncoder(t);
|
this.componentEncoder = factory.loadEncoder(t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -62,11 +62,11 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
}
|
}
|
||||||
Object[] array = value.toArray();
|
Object[] array = value.toArray();
|
||||||
if (array.length == 0) {
|
if (array.length == 0) {
|
||||||
out.writeArrayB(0, encoder, array);
|
out.writeArrayB(0, componentEncoder, array);
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.encoder == null) {
|
if (this.componentEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -77,7 +77,7 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out.writeArrayB(array.length, encoder, array) < 0) {
|
if (out.writeArrayB(array.length, componentEncoder, array) < 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Object v : array) {
|
for (Object v : array) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
@@ -89,7 +89,7 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
|
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
|
||||||
encoder.convertTo(out, value);
|
componentEncoder.convertTo(out, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -97,8 +97,11 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Encodeable<Writer, Object> getEncoder() {
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
return encoder;
|
return componentEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentEncoder == null ? null : componentEncoder.getType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
import java.util.function.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化的数据输出流
|
* 序列化的数据输出流
|
||||||
@@ -23,6 +25,12 @@ public abstract class Writer {
|
|||||||
//convertTo时是否以指定Type的ObjectEncoder进行处理
|
//convertTo时是否以指定Type的ObjectEncoder进行处理
|
||||||
protected Type specify;
|
protected Type specify;
|
||||||
|
|
||||||
|
//对某个字段值进行动态处理
|
||||||
|
protected BiFunction<Attribute, Object, Object> objFieldFunc;
|
||||||
|
|
||||||
|
//对某个对象进行动态扩展字段值处理
|
||||||
|
protected Function<Object, ConvertField[]> objExtFunc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置specify
|
* 设置specify
|
||||||
*
|
*
|
||||||
@@ -38,6 +46,11 @@ public abstract class Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean recycle() {
|
||||||
|
this.objFieldFunc = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回specify
|
* 返回specify
|
||||||
*
|
*
|
||||||
@@ -105,7 +118,12 @@ public abstract class Writer {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void writeObjectField(final EnMember member, Object obj) {
|
public void writeObjectField(final EnMember member, Object obj) {
|
||||||
Object value = member.attribute.get(obj);
|
Object value;
|
||||||
|
if (objFieldFunc == null) {
|
||||||
|
value = member.attribute.get(obj);
|
||||||
|
} else {
|
||||||
|
value = objFieldFunc.apply(member.attribute, obj);
|
||||||
|
}
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
if (tiny()) {
|
if (tiny()) {
|
||||||
if (member.istring) {
|
if (member.istring) {
|
||||||
@@ -114,11 +132,49 @@ public abstract class Writer {
|
|||||||
if (!((Boolean) value)) return;
|
if (!((Boolean) value)) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.writeFieldName(member);
|
Attribute attr = member.getAttribute();
|
||||||
|
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
|
||||||
member.encoder.convertTo(this, value);
|
member.encoder.convertTo(this, value);
|
||||||
this.comma = true;
|
this.comma = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出一个对象的某个扩展字段
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param fieldName 字段名称
|
||||||
|
* @param fieldType 字段类型
|
||||||
|
* @param fieldPos 字段顺序
|
||||||
|
* @param anyEncoder Encoder
|
||||||
|
* @param value 写入的字段对象
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) {
|
||||||
|
if (value == null) return;
|
||||||
|
if (fieldType == null) fieldType = value.getClass();
|
||||||
|
if (tiny() && fieldType instanceof Class) {
|
||||||
|
Class clazz = (Class) fieldType;
|
||||||
|
if (CharSequence.class.isAssignableFrom(clazz)) {
|
||||||
|
if (((CharSequence) value).length() == 0) return;
|
||||||
|
} else if (clazz == boolean.class || clazz == Boolean.class) {
|
||||||
|
if (!((Boolean) value)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.writeFieldName(fieldName, fieldType, fieldPos);
|
||||||
|
anyEncoder.convertTo(this, value);
|
||||||
|
this.comma = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出一个字段名
|
||||||
|
*
|
||||||
|
* @param member 字段
|
||||||
|
*/
|
||||||
|
public final void writeFieldName(final EnMember member) {
|
||||||
|
Attribute attr = member.getAttribute();
|
||||||
|
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出一个对象后的操作
|
* 输出一个对象后的操作
|
||||||
*
|
*
|
||||||
@@ -130,12 +186,12 @@ public abstract class Writer {
|
|||||||
* 输出一个数组前的操作
|
* 输出一个数组前的操作
|
||||||
*
|
*
|
||||||
* @param size 数组长度
|
* @param size 数组长度
|
||||||
* @param encoder Encodeable
|
* @param componentEncoder Encodeable
|
||||||
* @param obj 对象
|
* @param obj 对象, 不一定是数组、Collection对象,也可能是伪Collection对象
|
||||||
*
|
*
|
||||||
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
||||||
*/
|
*/
|
||||||
public abstract int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj);
|
public abstract int writeArrayB(int size, Encodeable<Writer, Object> componentEncoder, Object obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出数组元素间的间隔符
|
* 输出数组元素间的间隔符
|
||||||
@@ -155,7 +211,7 @@ public abstract class Writer {
|
|||||||
* @param size map大小
|
* @param size map大小
|
||||||
* @param keyEncoder Encodeable
|
* @param keyEncoder Encodeable
|
||||||
* @param valueEncoder Encodeable
|
* @param valueEncoder Encodeable
|
||||||
* @param obj 对象
|
* @param obj 对象, 不一定是Map对象,也可能是伪Map对象
|
||||||
*
|
*
|
||||||
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
||||||
*/
|
*/
|
||||||
@@ -176,9 +232,11 @@ public abstract class Writer {
|
|||||||
/**
|
/**
|
||||||
* 输出一个字段名
|
* 输出一个字段名
|
||||||
*
|
*
|
||||||
* @param member 字段的EnMember对象
|
* @param fieldName 字段名称
|
||||||
|
* @param fieldType 字段类型
|
||||||
|
* @param fieldPos 字段顺序
|
||||||
*/
|
*/
|
||||||
public abstract void writeFieldName(EnMember member);
|
public abstract void writeFieldName(String fieldName, Type fieldType, int fieldPos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写入一个boolean值
|
* 写入一个boolean值
|
||||||
@@ -256,4 +314,11 @@ public abstract class Writer {
|
|||||||
* @param value String值
|
* @param value String值
|
||||||
*/
|
*/
|
||||||
public abstract void writeString(String value);
|
public abstract void writeString(String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入一个StringConvertWrapper值
|
||||||
|
*
|
||||||
|
* @param value StringConvertWrapper值
|
||||||
|
*/
|
||||||
|
public abstract void writeWrapper(StringWrapper value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.redkale.convert.bson;
|
|||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import static org.redkale.convert.Reader.SIGN_NULL;
|
import static org.redkale.convert.Reader.SIGN_NULL;
|
||||||
|
import org.redkale.convert.ext.ByteSimpledCoder;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,18 +49,38 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position()));
|
return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) {
|
||||||
|
short bt = readShort();
|
||||||
|
if (bt == Reader.SIGN_NULL) return bt;
|
||||||
|
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 member DeMember
|
||||||
* @param decoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param componentDecoder Decodeable
|
||||||
|
*
|
||||||
* @return 数组长度或 SIGN_NULL
|
* @return 数组长度或 SIGN_NULL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final int readArrayB(DeMember member, Decodeable decoder) {
|
public final int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) {
|
||||||
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();
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public class BsonByteBufferWriter extends BsonWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
this.buffers = null;
|
this.buffers = null;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import org.redkale.util.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||||
|
|
||||||
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
||||||
|
|
||||||
@@ -59,6 +59,21 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
return BsonFactory.root().getConvert();
|
return BsonFactory.root().getConvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||||
|
return newConvert(fieldFunc, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||||
|
return new BsonConvert(getFactory(), tiny) {
|
||||||
|
@Override
|
||||||
|
protected <S extends BsonWriter> S configWrite(S writer) {
|
||||||
|
return fieldFunc(writer, fieldFunc, objExtFunc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
||||||
return new BsonByteBufferReader((ConvertMask) null, buffers);
|
return new BsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
@@ -78,11 +93,11 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ writer -----------------------------------------------------------
|
//------------------------------ writer -----------------------------------------------------------
|
||||||
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
|
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
|
||||||
return new BsonByteBufferWriter(tiny, supplier);
|
return configWrite(new BsonByteBufferWriter(tiny, supplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter pollBsonWriter(final OutputStream out) {
|
public BsonWriter pollBsonWriter(final OutputStream out) {
|
||||||
return new BsonStreamWriter(tiny, out);
|
return configWrite(new BsonStreamWriter(tiny, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter pollBsonWriter() {
|
public BsonWriter pollBsonWriter() {
|
||||||
@@ -94,6 +109,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertFrom -----------------------------------------------------------
|
//------------------------------ convertFrom -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
||||||
if (bytes == null) return null;
|
if (bytes == null) return null;
|
||||||
return convertFrom(type, bytes, 0, bytes.length);
|
return convertFrom(type, bytes, 0, bytes.length);
|
||||||
@@ -173,33 +189,33 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
factory.loadEncoder(value.getClass()).convertTo(new BsonStreamWriter(tiny, out), value);
|
factory.loadEncoder(value.getClass()).convertTo(pollBsonWriter(out), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||||
if (type == null) return;
|
if (type == null) return;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
factory.loadEncoder(type).convertTo(new BsonStreamWriter(tiny, out), value);
|
factory.loadEncoder(type).convertTo(pollBsonWriter(out), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void convertMapTo(final OutputStream out, final Object... values) {
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(new BsonStreamWriter(tiny, out), values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(pollBsonWriter(out), values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -211,7 +227,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -223,7 +239,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,8 +6,12 @@
|
|||||||
package org.redkale.convert.bson;
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.util.AnyValue;
|
import org.redkale.convert.ext.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BSON的ConvertFactory
|
* BSON的ConvertFactory
|
||||||
@@ -26,6 +30,16 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
static final Encodeable objectEncoder = instance.loadEncoder(Object.class);
|
static final Encodeable objectEncoder = instance.loadEncoder(Object.class);
|
||||||
|
|
||||||
|
static final Decodeable skipArrayDecoder = new SkipArrayDecoder(instance, Object[].class);
|
||||||
|
|
||||||
|
static final Decodeable skipCollectionDecoder = new SkipCollectionDecoder(instance, new TypeToken<Collection<Object>>() {
|
||||||
|
}.getType());
|
||||||
|
|
||||||
|
static final Decodeable skipStreamDecoder = new SkipStreamDecoder(instance, new TypeToken<Stream<Object>>() {
|
||||||
|
}.getType());
|
||||||
|
|
||||||
|
static final Decodeable skipMapDecoder = new SkipMapDecoder(instance, Map.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
instance.register(Serializable.class, objectDecoder);
|
instance.register(Serializable.class, objectDecoder);
|
||||||
instance.register(Serializable.class, objectEncoder);
|
instance.register(Serializable.class, objectEncoder);
|
||||||
@@ -89,4 +103,110 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static byte typeEnum(final Type type) {
|
||||||
|
return typeEnum(TypeToken.typeToClass(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static byte typeEnum(final Class type) {
|
||||||
|
Objects.requireNonNull(type);
|
||||||
|
byte typeval = 127; //字段的类型值
|
||||||
|
if (type == boolean.class || type == Boolean.class) {
|
||||||
|
typeval = 11;
|
||||||
|
} else if (type == byte.class || type == Byte.class) {
|
||||||
|
typeval = 12;
|
||||||
|
} else if (type == short.class || type == Short.class) {
|
||||||
|
typeval = 13;
|
||||||
|
} else if (type == char.class || type == Character.class) {
|
||||||
|
typeval = 14;
|
||||||
|
} else if (type == int.class || type == Integer.class) {
|
||||||
|
typeval = 15;
|
||||||
|
} else if (type == long.class || type == Long.class) {
|
||||||
|
typeval = 16;
|
||||||
|
} else if (type == float.class || type == Float.class) {
|
||||||
|
typeval = 17;
|
||||||
|
} else if (type == double.class || type == Double.class) {
|
||||||
|
typeval = 18;
|
||||||
|
} else if (type == String.class) {
|
||||||
|
typeval = 19;
|
||||||
|
} else if (type == boolean[].class || type == Boolean[].class) {
|
||||||
|
typeval = 21;
|
||||||
|
} else if (type == byte[].class || type == Byte[].class) {
|
||||||
|
typeval = 22;
|
||||||
|
} else if (type == short[].class || type == Short[].class) {
|
||||||
|
typeval = 23;
|
||||||
|
} else if (type == char[].class || type == Character[].class) {
|
||||||
|
typeval = 24;
|
||||||
|
} else if (type == int[].class || type == Integer[].class) {
|
||||||
|
typeval = 25;
|
||||||
|
} else if (type == long[].class || type == Long[].class) {
|
||||||
|
typeval = 26;
|
||||||
|
} else if (type == float[].class || type == Float[].class) {
|
||||||
|
typeval = 27;
|
||||||
|
} else if (type == double[].class || type == Double[].class) {
|
||||||
|
typeval = 28;
|
||||||
|
} else if (type == String[].class) {
|
||||||
|
typeval = 29;
|
||||||
|
} else if (type.isArray()) {
|
||||||
|
typeval = 81;
|
||||||
|
} else if (Collection.class.isAssignableFrom(type)) {
|
||||||
|
typeval = 82;
|
||||||
|
} else if (Stream.class.isAssignableFrom(type)) {
|
||||||
|
typeval = 83;
|
||||||
|
} else if (Map.class.isAssignableFrom(type)) {
|
||||||
|
typeval = 84;
|
||||||
|
}
|
||||||
|
return typeval;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Decodeable typeEnum(final byte typeval) {
|
||||||
|
switch (typeval) {
|
||||||
|
case 11:
|
||||||
|
return BoolSimpledCoder.instance;
|
||||||
|
case 12:
|
||||||
|
return ByteSimpledCoder.instance;
|
||||||
|
case 13:
|
||||||
|
return ShortSimpledCoder.instance;
|
||||||
|
case 14:
|
||||||
|
return CharSimpledCoder.instance;
|
||||||
|
case 15:
|
||||||
|
return IntSimpledCoder.instance;
|
||||||
|
case 16:
|
||||||
|
return LongSimpledCoder.instance;
|
||||||
|
case 17:
|
||||||
|
return FloatSimpledCoder.instance;
|
||||||
|
case 18:
|
||||||
|
return DoubleSimpledCoder.instance;
|
||||||
|
case 19:
|
||||||
|
return StringSimpledCoder.instance;
|
||||||
|
case 21:
|
||||||
|
return BoolArraySimpledCoder.instance;
|
||||||
|
case 22:
|
||||||
|
return ByteArraySimpledCoder.instance;
|
||||||
|
case 23:
|
||||||
|
return ShortArraySimpledCoder.instance;
|
||||||
|
case 24:
|
||||||
|
return CharArraySimpledCoder.instance;
|
||||||
|
case 25:
|
||||||
|
return IntArraySimpledCoder.instance;
|
||||||
|
case 26:
|
||||||
|
return LongArraySimpledCoder.instance;
|
||||||
|
case 27:
|
||||||
|
return FloatArraySimpledCoder.instance;
|
||||||
|
case 28:
|
||||||
|
return DoubleArraySimpledCoder.instance;
|
||||||
|
case 29:
|
||||||
|
return StringArraySimpledCoder.instance;
|
||||||
|
case 81:
|
||||||
|
return skipArrayDecoder;
|
||||||
|
case 82:
|
||||||
|
return skipCollectionDecoder;
|
||||||
|
case 83:
|
||||||
|
return skipStreamDecoder;
|
||||||
|
case 84:
|
||||||
|
return skipMapDecoder;
|
||||||
|
case 127:
|
||||||
|
return BsonFactory.objectDecoder;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,53 +93,27 @@ public class BsonReader extends Reader {
|
|||||||
final byte val = this.typeval;
|
final byte val = this.typeval;
|
||||||
this.typeval = 0;
|
this.typeval = 0;
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1: readBoolean();
|
case 11: readBoolean();
|
||||||
break;
|
break;
|
||||||
case 2: readByte();
|
case 12: readByte();
|
||||||
break;
|
break;
|
||||||
case 3: readShort();
|
case 13: readShort();
|
||||||
break;
|
break;
|
||||||
case 4: readChar();
|
case 14: readChar();
|
||||||
break;
|
break;
|
||||||
case 5: readInt();
|
case 15: readInt();
|
||||||
break;
|
break;
|
||||||
case 6: readLong();
|
case 16: readLong();
|
||||||
break;
|
break;
|
||||||
case 7: readFloat();
|
case 17: readFloat();
|
||||||
break;
|
break;
|
||||||
case 8: readDouble();
|
case 18: readDouble();
|
||||||
break;
|
break;
|
||||||
case 9: readString();
|
case 19: readString();
|
||||||
break;
|
break;
|
||||||
case 101:
|
default:
|
||||||
BoolArraySimpledCoder.instance.convertFrom(this);
|
Decodeable decoder = BsonFactory.typeEnum(val);
|
||||||
break;
|
if (decoder != null) decoder.convertFrom(this);
|
||||||
case 102:
|
|
||||||
ByteArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 103:
|
|
||||||
ShortArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 104:
|
|
||||||
CharArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 105:
|
|
||||||
IntArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 106:
|
|
||||||
LongArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 107:
|
|
||||||
FloatArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 108:
|
|
||||||
DoubleArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 109:
|
|
||||||
StringArraySimpledCoder.instance.convertFrom(this);
|
|
||||||
break;
|
|
||||||
case 127:
|
|
||||||
BsonFactory.objectDecoder.convertFrom(this);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,8 +145,17 @@ public class BsonReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int readMapB(DeMember member, Decodeable keydecoder) {
|
public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) {
|
||||||
return readArrayB(member, keydecoder);
|
short bt = readShort();
|
||||||
|
if (bt == Reader.SIGN_NULL) return bt;
|
||||||
|
int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
||||||
|
byte kt = readByte();
|
||||||
|
byte vt = readByte();
|
||||||
|
if (typevals != null) {
|
||||||
|
typevals[0] = kt;
|
||||||
|
typevals[1] = vt;
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,10 +168,15 @@ public class BsonReader extends Reader {
|
|||||||
* @return 数组长度或SIGN_NULL
|
* @return 数组长度或SIGN_NULL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int readArrayB(DeMember member, Decodeable decoder) {
|
public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { //componentDecoder可能为null
|
||||||
short bt = readShort();
|
short bt = readShort();
|
||||||
if (bt == Reader.SIGN_NULL) return bt;
|
if (bt == Reader.SIGN_NULL) return bt;
|
||||||
return (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
||||||
|
if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) {
|
||||||
|
byte comval = readByte();
|
||||||
|
if (typevals != null) typevals[0] = comval;
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,7 +251,7 @@ public class BsonReader extends Reader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final byte[] readByteArray() {
|
public final byte[] readByteArray() {
|
||||||
int len = readArrayB(null, null);
|
int len = readArrayB(null, null, null);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
@@ -358,4 +346,9 @@ public class BsonReader extends Reader {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueType readType() {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.bson;
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
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.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +44,7 @@ public class BsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected BsonWriter(byte[] bs) {
|
protected BsonWriter(byte[] bs) {
|
||||||
this.content = bs;
|
this.content = bs == null ? new byte[0] : bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter() {
|
public BsonWriter() {
|
||||||
@@ -96,10 +98,12 @@ public class BsonWriter extends Writer {
|
|||||||
count += len;
|
count += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
if (this.content.length > defaultSize) {
|
if (this.content != null && this.content.length > defaultSize) {
|
||||||
this.content = new byte[defaultSize];
|
this.content = new byte[defaultSize];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -197,50 +201,10 @@ public class BsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeFieldName(EnMember member) {
|
public final void writeFieldName(String fieldName, Type fieldType, int fieldPos) {
|
||||||
Attribute attribute = member.getAttribute();
|
|
||||||
writeByte(BsonReader.SIGN_HASNEXT);
|
writeByte(BsonReader.SIGN_HASNEXT);
|
||||||
writeSmallString(attribute.field());
|
writeSmallString(fieldName);
|
||||||
byte typeval = 127; //字段的类型值
|
writeByte(BsonFactory.typeEnum(fieldType));
|
||||||
final Class type = attribute.type();
|
|
||||||
if (type == boolean.class || type == Boolean.class) {
|
|
||||||
typeval = 1;
|
|
||||||
} else if (type == byte.class || type == Byte.class) {
|
|
||||||
typeval = 2;
|
|
||||||
} else if (type == short.class || type == Short.class) {
|
|
||||||
typeval = 3;
|
|
||||||
} else if (type == char.class || type == Character.class) {
|
|
||||||
typeval = 4;
|
|
||||||
} else if (type == int.class || type == Integer.class) {
|
|
||||||
typeval = 5;
|
|
||||||
} else if (type == long.class || type == Long.class) {
|
|
||||||
typeval = 6;
|
|
||||||
} else if (type == float.class || type == Float.class) {
|
|
||||||
typeval = 7;
|
|
||||||
} else if (type == double.class || type == Double.class) {
|
|
||||||
typeval = 8;
|
|
||||||
} else if (type == String.class) {
|
|
||||||
typeval = 9;
|
|
||||||
} else if (type == boolean[].class || type == Boolean[].class) {
|
|
||||||
typeval = 101;
|
|
||||||
} else if (type == byte[].class || type == Byte[].class) {
|
|
||||||
typeval = 102;
|
|
||||||
} else if (type == short[].class || type == Short[].class) {
|
|
||||||
typeval = 103;
|
|
||||||
} else if (type == char[].class || type == Character[].class) {
|
|
||||||
typeval = 104;
|
|
||||||
} else if (type == int[].class || type == Integer[].class) {
|
|
||||||
typeval = 105;
|
|
||||||
} else if (type == long[].class || type == Long[].class) {
|
|
||||||
typeval = 106;
|
|
||||||
} else if (type == float[].class || type == Float[].class) {
|
|
||||||
typeval = 107;
|
|
||||||
} else if (type == double[].class || type == Double[].class) {
|
|
||||||
typeval = 108;
|
|
||||||
} else if (type == String[].class) {
|
|
||||||
typeval = 109;
|
|
||||||
}
|
|
||||||
writeByte(typeval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -279,14 +243,22 @@ public class BsonWriter extends Writer {
|
|||||||
writeTo(bytes);
|
writeTo(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeWrapper(StringWrapper value) {
|
||||||
|
this.writeString(value == null ? null : value.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeNull() {
|
public final void writeNull() {
|
||||||
writeShort(Reader.SIGN_NULL);
|
writeShort(Reader.SIGN_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
|
public final int writeArrayB(int size, Encodeable<Writer, Object> componentEncoder, Object obj) {
|
||||||
writeInt(size);
|
writeInt(size);
|
||||||
|
if (componentEncoder != null && componentEncoder != ByteSimpledCoder.instance) {
|
||||||
|
writeByte(BsonFactory.typeEnum(componentEncoder.getType()));
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +272,9 @@ public class BsonWriter extends Writer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
|
public int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
|
||||||
writeArrayB(size, valueEncoder, obj);
|
writeInt(size);
|
||||||
|
writeByte(BsonFactory.typeEnum(keyEncoder.getType()));
|
||||||
|
writeByte(BsonFactory.typeEnum(valueEncoder.getType()));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
33
src/org/redkale/convert/bson/SkipArrayDecoder.java
Normal file
33
src/org/redkale/convert/bson/SkipArrayDecoder.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数组的反序列化操作类 <br>
|
||||||
|
* 对象数组的反序列化,不包含int[]、long[]这样的primitive class数组。 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的数组元素类型
|
||||||
|
*/
|
||||||
|
public class SkipArrayDecoder<T> extends ArrayDecoder<T> {
|
||||||
|
|
||||||
|
public SkipArrayDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/org/redkale/convert/bson/SkipCollectionDecoder.java
Normal file
32
src/org/redkale/convert/bson/SkipCollectionDecoder.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection的反序列化操作类 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的集合元素类型
|
||||||
|
*/
|
||||||
|
public class SkipCollectionDecoder<T> extends CollectionDecoder<T> {
|
||||||
|
|
||||||
|
public SkipCollectionDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/org/redkale/convert/bson/SkipMapDecoder.java
Normal file
38
src/org/redkale/convert/bson/SkipMapDecoder.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map的反序列化操作类 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <K> Map key的数据类型
|
||||||
|
* @param <V> Map value的数据类型
|
||||||
|
*/
|
||||||
|
public class SkipMapDecoder<K, V> extends MapDecoder<K, V> {
|
||||||
|
|
||||||
|
public SkipMapDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, K> getKeyDecoder(Decodeable<Reader, K> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, V> getValueDecoder(Decodeable<Reader, V> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[1]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/org/redkale/convert/bson/SkipStreamDecoder.java
Normal file
32
src/org/redkale/convert/bson/SkipStreamDecoder.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream的反序列化操作类 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的集合元素类型
|
||||||
|
*/
|
||||||
|
public class SkipStreamDecoder<T> extends StreamDecoder<T> {
|
||||||
|
|
||||||
|
public SkipStreamDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
super(factory, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
if (typevals != null) return BsonFactory.typeEnum(typevals[0]);
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ public final class BoolArraySimpledCoder<R extends Reader, W extends Writer> ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean[] convertFrom(R in) {
|
public boolean[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, BoolSimpledCoder.instance);
|
int len = in.readArrayB(null, null, BoolSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class ByteBufferSimpledCoder<R extends Reader, W extends Writer> ex
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer convertFrom(R in) {
|
public ByteBuffer convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, ByteSimpledCoder.instance);
|
int len = in.readArrayB(null, null, ByteSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public final class CharArraySimpledCoder<R extends Reader, W extends Writer> ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char[] convertFrom(R in) {
|
public char[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, CharSimpledCoder.instance);
|
int len = in.readArrayB(null, null, CharSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import org.redkale.convert.*;
|
|||||||
/**
|
/**
|
||||||
* CharSequence 的SimpledCoder实现
|
* CharSequence 的SimpledCoder实现
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
* @param <R> Reader输入的子类型
|
* @param <R> Reader输入的子类型
|
||||||
* @param <W> Writer输出的子类型
|
* @param <W> Writer输出的子类型
|
||||||
@@ -28,4 +30,20 @@ public class CharSequenceSimpledCoder<R extends Reader, W extends Writer> extend
|
|||||||
public CharSequence convertFrom(R in) {
|
public CharSequence convertFrom(R in) {
|
||||||
return in.readString();
|
return in.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class StringBuilderSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringBuilder> {
|
||||||
|
|
||||||
|
public static final StringBuilderSimpledCoder instance = new StringBuilderSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, StringBuilder value) {
|
||||||
|
out.writeString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringBuilder convertFrom(R in) {
|
||||||
|
String rs = in.readString();
|
||||||
|
return rs == null ? null : new StringBuilder(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> e
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double[] convertFrom(R in) {
|
public double[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, DoubleSimpledCoder.instance);
|
int len = in.readArrayB(null, null, DoubleSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
41
src/org/redkale/convert/ext/DurationSimpledCoder.java
Normal file
41
src/org/redkale/convert/ext/DurationSimpledCoder.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public class DurationSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Duration> {
|
||||||
|
|
||||||
|
public static final DurationSimpledCoder instance = new DurationSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, Duration value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
out.writeLong(value.toNanos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Duration convertFrom(R in) {
|
||||||
|
String value = in.readSmallString();
|
||||||
|
if (value == null) return null;
|
||||||
|
return Duration.ofNanos(Long.parseLong(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ import org.redkale.convert.*;
|
|||||||
*/
|
*/
|
||||||
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
||||||
|
|
||||||
public static final PatternSimpledCoder instance = new PatternSimpledCoder();
|
public static final FileSimpledCoder instance = new FileSimpledCoder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void convertTo(W out, File value) {
|
public void convertTo(W out, File value) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public final class FloatArraySimpledCoder<R extends Reader, W extends Writer> ex
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float[] convertFrom(R in) {
|
public float[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, FloatSimpledCoder.instance);
|
int len = in.readArrayB(null, null, FloatSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class IntArraySimpledCoder<R extends Reader, W extends Writer> exte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] convertFrom(R in) {
|
public int[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, IntSimpledCoder.instance);
|
int len = in.readArrayB(null, null, IntSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class LongArraySimpledCoder<R extends Reader, W extends Writer> ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long[] convertFrom(R in) {
|
public long[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, LongSimpledCoder.instance);
|
int len = in.readArrayB(null, null, LongSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public final class ShortArraySimpledCoder<R extends Reader, W extends Writer> ex
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short[] convertFrom(R in) {
|
public short[] convertFrom(R in) {
|
||||||
int len = in.readArrayB(null, ShortSimpledCoder.instance);
|
int len = in.readArrayB(null, null, ShortSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public final class StringArraySimpledCoder<R extends Reader, W extends Writer> e
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String[] convertFrom(R in, DeMember member) {
|
public String[] convertFrom(R in, DeMember member) {
|
||||||
int len = in.readArrayB(member, StringSimpledCoder.instance);
|
int len = in.readArrayB(member, null, StringSimpledCoder.instance);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
35
src/org/redkale/convert/ext/StringWrapperSimpledCoder.java
Normal file
35
src/org/redkale/convert/ext/StringWrapperSimpledCoder.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.util.StringWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public final class StringWrapperSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringWrapper> {
|
||||||
|
|
||||||
|
public static final StringWrapperSimpledCoder instance = new StringWrapperSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, StringWrapper value) {
|
||||||
|
out.writeWrapper(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringWrapper convertFrom(R in) {
|
||||||
|
return new StringWrapper(in.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -140,12 +140,13 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
* 判断下一个非空白字符是否为[
|
* 判断下一个非空白字符是否为[
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
|
* @param typevals byte[]
|
||||||
* @param decoder Decodeable
|
* @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;
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
this.charset = null;
|
this.charset = null;
|
||||||
@@ -114,7 +115,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
int byteLength = quote ? 2 : 0;
|
int byteLength = quote ? 2 : 0;
|
||||||
ByteBuffer bb = null;
|
ByteBuffer bb = null;
|
||||||
if (charset == null) {
|
if (charset == null) {
|
||||||
byteLength += encodeUTF8Length(chs, start, len);
|
byteLength += Utility.encodeUTF8Length(chs, start, len);
|
||||||
} else {
|
} else {
|
||||||
bb = charset.encode(CharBuffer.wrap(chs, start, len));
|
bb = charset.encode(CharBuffer.wrap(chs, start, len));
|
||||||
byteLength += bb.remaining();
|
byteLength += bb.remaining();
|
||||||
@@ -133,6 +134,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
} else if (c < 0x800) {
|
} else if (c < 0x800) {
|
||||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (Character.isSurrogate(c)) { //连取两个
|
||||||
|
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||||
|
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||||
|
i++;
|
||||||
} else {
|
} else {
|
||||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
@@ -154,7 +162,34 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
if (charset == null) { //UTF-8
|
if (charset == null) { //UTF-8
|
||||||
final int limit = start + len;
|
final int limit = start + len;
|
||||||
for (int i = start; i < limit; i++) {
|
for (int i = start; i < limit; i++) {
|
||||||
buffer = putUTF8Char(buffer, chs[i]);
|
char c = chs[i];
|
||||||
|
if (c < 0x80) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) c);
|
||||||
|
} else if (c < 0x800) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (Character.isSurrogate(c)) { //连取两个
|
||||||
|
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (bb.hasRemaining()) {
|
while (bb.hasRemaining()) {
|
||||||
@@ -168,50 +203,18 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ByteBuffer putUTF8Char(ByteBuffer buffer, char c) {
|
|
||||||
if (c < 0x80) {
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) c);
|
|
||||||
} else if (c < 0x800) {
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
|
||||||
} else {
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ByteBuffer nextByteBuffer() {
|
private ByteBuffer nextByteBuffer() {
|
||||||
this.buffers[this.index].flip();
|
this.buffers[this.index].flip();
|
||||||
return this.buffers[++this.index];
|
return this.buffers[++this.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int encodeUTF8Length(final char[] text, final int start, final int len) {
|
|
||||||
char c;
|
|
||||||
int size = 0;
|
|
||||||
final char[] chars = text;
|
|
||||||
final int limit = start + len;
|
|
||||||
for (int i = start; i < limit; i++) {
|
|
||||||
c = chars[i];
|
|
||||||
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) {
|
protected static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) {
|
||||||
char c;
|
char c;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
final char[] chars = text;
|
final char[] chs = text;
|
||||||
final int limit = start + len;
|
final int limit = start + len;
|
||||||
for (int i = start; i < limit; i++) {
|
for (int i = start; i < limit; i++) {
|
||||||
c = chars[i];
|
c = chs[i];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\n': size += 2;
|
case '\n': size += 2;
|
||||||
break;
|
break;
|
||||||
@@ -224,7 +227,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
case '"': size += 2;
|
case '"': size += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
|
size += (c < 0x80 ? 1 : (c < 0x800 || Character.isSurrogate(c) ? 2 : 3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,19 +241,39 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
* @param value String值
|
* @param value String值
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(final boolean quote, final String value) {
|
public void writeLatin1To(final boolean quote, final String value) {
|
||||||
char[] chs = Utility.charArray(value);
|
byte[] bs = Utility.byteArray(value);
|
||||||
writeTo(-1, quote, chs, 0, chs.length);
|
int expandsize = expand(bs.length + (quote ? 2 : 0));
|
||||||
|
if (expandsize == 0) {// 只需要一个buffer
|
||||||
|
final ByteBuffer buffer = this.buffers[index];
|
||||||
|
if (quote) buffer.put((byte) '"');
|
||||||
|
buffer.put(bs);
|
||||||
|
if (quote) buffer.put((byte) '"');
|
||||||
|
} else {
|
||||||
|
ByteBuffer buffer = this.buffers[index];
|
||||||
|
if (quote) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) '"');
|
||||||
|
}
|
||||||
|
for (byte b : bs) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put(b);
|
||||||
|
}
|
||||||
|
if (quote) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) '"');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeInt(int value) {
|
public void writeInt(int value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeLong(long value) {
|
public void writeLong(long value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -288,7 +311,8 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
if (expandsize == 0) { // 只需要一个buffer
|
if (expandsize == 0) { // 只需要一个buffer
|
||||||
final ByteBuffer buffer = this.buffers[index];
|
final ByteBuffer buffer = this.buffers[index];
|
||||||
buffer.put((byte) '"');
|
buffer.put((byte) '"');
|
||||||
for (char c : chs) {
|
for (int i = 0; i < chs.length; i++) {
|
||||||
|
char c = chs[i];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\n': buffer.put((byte) '\\').put((byte) 'n');
|
case '\n': buffer.put((byte) '\\').put((byte) 'n');
|
||||||
break;
|
break;
|
||||||
@@ -306,6 +330,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
} else if (c < 0x800) {
|
} else if (c < 0x800) {
|
||||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (Character.isSurrogate(c)) { //连取两个
|
||||||
|
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||||
|
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||||
|
i++;
|
||||||
} else {
|
} else {
|
||||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.redkale.util.*;
|
|||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||||
|
|
||||||
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() {
|
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
@@ -46,6 +46,21 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
return JsonFactory.root().getConvert();
|
return JsonFactory.root().getConvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||||
|
return newConvert(fieldFunc, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||||
|
return new JsonConvert(getFactory(), tiny) {
|
||||||
|
@Override
|
||||||
|
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||||
|
return fieldFunc(writer, fieldFunc, objExtFunc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
||||||
return new JsonByteBufferReader((ConvertMask) null, buffers);
|
return new JsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
@@ -65,19 +80,19 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ writer -----------------------------------------------------------
|
//------------------------------ writer -----------------------------------------------------------
|
||||||
public JsonByteBufferWriter pollJsonWriter(final Supplier<ByteBuffer> supplier) {
|
public JsonByteBufferWriter pollJsonWriter(final Supplier<ByteBuffer> supplier) {
|
||||||
return new JsonByteBufferWriter(tiny, supplier);
|
return configWrite(new JsonByteBufferWriter(tiny, supplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter(final OutputStream out) {
|
public JsonWriter pollJsonWriter(final OutputStream out) {
|
||||||
return new JsonStreamWriter(tiny, out);
|
return configWrite(new JsonStreamWriter(tiny, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter(final Charset charset, final OutputStream out) {
|
public JsonWriter pollJsonWriter(final Charset charset, final OutputStream out) {
|
||||||
return new JsonStreamWriter(tiny, charset, out);
|
return configWrite(new JsonStreamWriter(tiny, charset, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter() {
|
public JsonWriter pollJsonWriter() {
|
||||||
return writerPool.get().tiny(tiny);
|
return configWrite(writerPool.get().tiny(tiny));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerJsonWriter(final JsonWriter writer) {
|
public void offerJsonWriter(final JsonWriter writer) {
|
||||||
@@ -85,6 +100,12 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertFrom -----------------------------------------------------------
|
//------------------------------ convertFrom -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
|
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
||||||
|
if (bytes == null) return null;
|
||||||
|
return convertFrom(type, new String(bytes, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
public <T> T convertFrom(final Type type, final String text) {
|
public <T> T convertFrom(final Type type, final String text) {
|
||||||
if (text == null) return null;
|
if (text == null) return null;
|
||||||
return convertFrom(type, Utility.charArray(text));
|
return convertFrom(type, Utility.charArray(text));
|
||||||
@@ -128,6 +149,52 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final String text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
return (V) convertFrom(Utility.charArray(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final char[] text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
return (V) convertFrom(text, 0, text.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final char[] text, final int start, final int len) {
|
||||||
|
if (text == null) return null;
|
||||||
|
final JsonReader in = readerPool.get();
|
||||||
|
in.setText(text, start, len);
|
||||||
|
Object rs = new AnyDecoder(factory).convertFrom(in);
|
||||||
|
readerPool.accept(in);
|
||||||
|
return (V) rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final InputStream in) {
|
||||||
|
if (in == null) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonStreamReader(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final ByteBuffer... buffers) {
|
||||||
|
if (buffers == null || buffers.length == 0) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final ConvertMask mask, final ByteBuffer... buffers) {
|
||||||
|
if (buffers == null || buffers.length == 0) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader(mask, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final JsonReader reader) {
|
||||||
|
if (reader == null) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(reader);
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ convertTo -----------------------------------------------------------
|
//------------------------------ convertTo -----------------------------------------------------------
|
||||||
@Override
|
@Override
|
||||||
public String convertTo(final Object value) {
|
public String convertTo(final Object value) {
|
||||||
@@ -139,7 +206,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
public String convertTo(final Type type, final Object value) {
|
public String convertTo(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
if (value == null) return "null";
|
if (value == null) return "null";
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
String result = writer.toString();
|
String result = writer.toString();
|
||||||
@@ -150,7 +217,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public String convertMapTo(final Object... values) {
|
public String convertMapTo(final Object... values) {
|
||||||
if (values == null) return "null";
|
if (values == null) return "null";
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
String result = writer.toString();
|
String result = writer.toString();
|
||||||
writerPool.accept(writer);
|
writerPool.accept(writer);
|
||||||
@@ -159,7 +226,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
convertTo(out, value.getClass(), value);
|
convertTo(out, value.getClass(), value);
|
||||||
}
|
}
|
||||||
@@ -168,9 +235,9 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||||
if (type == null) return;
|
if (type == null) return;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
byte[] bs = writer.toBytes();
|
byte[] bs = writer.toBytes();
|
||||||
@@ -185,9 +252,9 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public void convertMapTo(final OutputStream out, final Object... values) {
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
byte[] bs = writer.toBytes();
|
byte[] bs = writer.toBytes();
|
||||||
writerPool.accept(writer);
|
writerPool.accept(writer);
|
||||||
@@ -202,7 +269,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -214,7 +281,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -227,7 +294,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -269,14 +336,14 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public JsonWriter convertToWriter(final Type type, final Object value) {
|
public JsonWriter convertToWriter(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
return writer;
|
return writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter convertMapToWriter(final Object... values) {
|
public JsonWriter convertMapToWriter(final Object... values) {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
return writer;
|
return writer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,7 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
|||||||
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
|
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
|
||||||
|
|
||||||
static {
|
static {
|
||||||
instance.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
|
||||||
instance.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
|
||||||
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
|
||||||
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
|
||||||
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
||||||
|
|
||||||
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
|
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
|
||||||
@@ -38,6 +35,12 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
private JsonFactory(JsonFactory parent, boolean tiny) {
|
private JsonFactory(JsonFactory parent, boolean tiny) {
|
||||||
super(parent, tiny);
|
super(parent, tiny);
|
||||||
|
if (parent == null) {
|
||||||
|
this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
||||||
|
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
||||||
|
this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
||||||
|
this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -158,6 +158,21 @@ public class JsonReader extends Reader {
|
|||||||
this.position--;
|
this.position--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ValueType readType() {
|
||||||
|
char ch = nextGoodChar();
|
||||||
|
if (ch == '{') {
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.MAP;
|
||||||
|
}
|
||||||
|
if (ch == '[') {
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.ARRAY;
|
||||||
|
}
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断下一个非空白字符是否为{
|
* 判断下一个非空白字符是否为{
|
||||||
*
|
*
|
||||||
@@ -168,6 +183,7 @@ public class JsonReader extends Reader {
|
|||||||
@Override
|
@Override
|
||||||
public String readObjectB(final Class clazz) {
|
public String readObjectB(final Class clazz) {
|
||||||
this.fieldIndex = 0; //必须要重置为0
|
this.fieldIndex = 0; //必须要重置为0
|
||||||
|
if (this.text.length == 0) return null;
|
||||||
char ch = this.text[++this.position];
|
char ch = this.text[++this.position];
|
||||||
if (ch == '{') return "";
|
if (ch == '{') return "";
|
||||||
if (ch <= ' ') {
|
if (ch <= ' ') {
|
||||||
@@ -190,13 +206,15 @@ 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
|
||||||
@@ -207,12 +225,14 @@ public class JsonReader extends Reader {
|
|||||||
* 判断下一个非空白字符是否为[
|
* 判断下一个非空白字符是否为[
|
||||||
*
|
*
|
||||||
* @param member DeMember
|
* @param member DeMember
|
||||||
* @param decoder Decodeable
|
* @param typevals byte[]
|
||||||
|
* @param componentDecoder Decodeable
|
||||||
*
|
*
|
||||||
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int readArrayB(DeMember member, Decodeable decoder) {
|
public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) {
|
||||||
|
if (this.text.length == 0) return SIGN_NULL;
|
||||||
char ch = this.text[++this.position];
|
char ch = this.text[++this.position];
|
||||||
if (ch == '[') return SIGN_NOLENGTH;
|
if (ch == '[') return SIGN_NOLENGTH;
|
||||||
if (ch == '{') return SIGN_NOLENGTH;
|
if (ch == '{') return SIGN_NOLENGTH;
|
||||||
@@ -333,7 +353,7 @@ public class JsonReader extends Reader {
|
|||||||
}
|
}
|
||||||
this.position = currpos - 1;
|
this.position = currpos - 1;
|
||||||
if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null;
|
if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null;
|
||||||
return new String(text0, start, len);
|
return new String(text0, start, len == eof ? (len + 1) : len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +494,7 @@ public class JsonReader extends Reader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final byte[] readByteArray() {
|
public final byte[] readByteArray() {
|
||||||
int len = readArrayB(null, null);
|
int len = readArrayB(null, null, null);
|
||||||
int contentLength = -1;
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
|||||||
@@ -87,19 +87,19 @@ class JsonStreamWriter extends JsonByteBufferWriter {
|
|||||||
* @param value String值
|
* @param value String值
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(final boolean quote, final String value) {
|
public void writeLatin1To(final boolean quote, final String value) {
|
||||||
char[] chs = Utility.charArray(value);
|
char[] chs = Utility.charArray(value);
|
||||||
writeTo(quote, chs, 0, chs.length);
|
writeTo(quote, chs, 0, chs.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeInt(int value) {
|
public void writeInt(int value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeLong(long value) {
|
public void writeLong(long value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.json;
|
package org.redkale.convert.json;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
@@ -88,7 +89,7 @@ public class JsonWriter extends Writer {
|
|||||||
* @param quote 是否加双引号
|
* @param quote 是否加双引号
|
||||||
* @param value 非null且不含需要转义的字符的String值
|
* @param value 非null且不含需要转义的字符的String值
|
||||||
*/
|
*/
|
||||||
public void writeTo(final boolean quote, final String value) {
|
public void writeLatin1To(final boolean quote, final String value) {
|
||||||
int len = value.length();
|
int len = value.length();
|
||||||
expand(len + (quote ? 2 : 0));
|
expand(len + (quote ? 2 : 0));
|
||||||
if (quote) content[count++] = '"';
|
if (quote) content[count++] = '"';
|
||||||
@@ -97,10 +98,12 @@ public class JsonWriter extends Writer {
|
|||||||
if (quote) content[count++] = '"';
|
if (quote) content[count++] = '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
if (this.content.length > defaultSize) {
|
if (this.content != null && this.content.length > defaultSize) {
|
||||||
this.content = new char[defaultSize];
|
this.content = new char[defaultSize];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -157,15 +160,15 @@ public class JsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeFieldName(EnMember member) {
|
public final void writeFieldName(String fieldName, Type fieldType, int fieldPos) {
|
||||||
if (this.comma) writeTo(',');
|
if (this.comma) writeTo(',');
|
||||||
writeTo(true, member.getAttribute().field());
|
writeLatin1To(true, fieldName);
|
||||||
writeTo(':');
|
writeTo(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeSmallString(String value) {
|
public final void writeSmallString(String value) {
|
||||||
writeTo(true, value);
|
writeLatin1To(true, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -311,12 +314,17 @@ public class JsonWriter extends Writer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeFloat(float value) {
|
public final void writeFloat(float value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeDouble(double value) {
|
public final void writeDouble(double value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeWrapper(StringWrapper value) {
|
||||||
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -346,7 +354,7 @@ public class JsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
|
public final int writeArrayB(int size, Encodeable<Writer, Object> componentEncoder, Object obj) {
|
||||||
writeTo('[');
|
writeTo('[');
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ package org.redkale.net;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -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,26 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
//关联的事件数, 小于1表示没有事件
|
//关联的事件数, 小于1表示没有事件
|
||||||
protected final AtomicInteger eventing = new AtomicInteger();
|
protected final AtomicInteger eventing = new AtomicInteger();
|
||||||
|
|
||||||
|
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 Supplier<ByteBuffer> getBufferSupplier() {
|
||||||
|
return this.bufferSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<ByteBuffer> getBufferConsumer() {
|
||||||
|
return this.bufferConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
public final long getLastReadTime() {
|
public final long getLastReadTime() {
|
||||||
return readtime;
|
return readtime;
|
||||||
}
|
}
|
||||||
@@ -61,6 +88,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 +114,13 @@ 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);
|
||||||
|
|
||||||
@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 +129,54 @@ 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;
|
||||||
|
}
|
||||||
|
// Thread thread = Thread.currentThread();
|
||||||
|
// if (thread instanceof IOThread) {
|
||||||
|
// return ((IOThread) thread).getBufferPool().get();
|
||||||
|
// }
|
||||||
|
return bufferSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(Buffer buffer) {
|
||||||
|
if (buffer == null) return;
|
||||||
|
// Thread thread = Thread.currentThread();
|
||||||
|
// if (thread instanceof IOThread) {
|
||||||
|
// ((IOThread) thread).getBufferPool().accept((ByteBuffer) buffer);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
bufferConsumer.accept((ByteBuffer) buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(Buffer... buffers) {
|
||||||
|
if (buffers == null) return;
|
||||||
|
Consumer<ByteBuffer> consumer = this.bufferConsumer;
|
||||||
|
// Thread thread = Thread.currentThread();
|
||||||
|
// if (thread instanceof IOThread) {
|
||||||
|
// consumer = ((IOThread) thread).getBufferPool();
|
||||||
|
// }
|
||||||
|
for (Buffer buffer : buffers) {
|
||||||
|
consumer.accept((ByteBuffer) buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer pollWriteBuffer() {
|
||||||
|
// Thread thread = Thread.currentThread();
|
||||||
|
// if (thread instanceof IOThread) {
|
||||||
|
// return ((IOThread) thread).getBufferPool().get();
|
||||||
|
// }
|
||||||
|
return bufferSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose() {//同close, 只是去掉throws IOException
|
public void dispose() {//同close, 只是去掉throws IOException
|
||||||
try {
|
try {
|
||||||
this.close();
|
this.close();
|
||||||
@@ -125,11 +199,20 @@ 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) {
|
||||||
|
Consumer<ByteBuffer> consumer = this.bufferConsumer;
|
||||||
|
// Thread thread = Thread.currentThread();
|
||||||
|
// if (thread instanceof IOThread) {
|
||||||
|
// consumer = ((IOThread) thread).getBufferPool();
|
||||||
|
// }
|
||||||
|
consumer.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 +257,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 +265,15 @@ 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 bufferPool ByteBuffer对象池
|
||||||
* @param address 连接点子
|
* @param address 连接点子
|
||||||
* @param sslContext SSLContext
|
* @param sslContext SSLContext
|
||||||
* @param group 连接AsynchronousChannelGroup
|
* @param group 连接AsynchronousChannelGroup
|
||||||
@@ -197,7 +282,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 +314,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 +328,80 @@ 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 ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch) {
|
||||||
return create(ch, null, 0, 0);
|
return create(bufferPool, ch, null, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch,
|
||||||
return new TcpAioAsyncConnection(ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
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 AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
return new TcpAioAsyncConnection(ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
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 AsynchronousSocketChannel ch, final SocketAddress addr0, final Context context) {
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch,
|
||||||
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
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 AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds,
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, 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, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0,
|
|
||||||
final Context context, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,8 @@
|
|||||||
package org.redkale.net;
|
package org.redkale.net;
|
||||||
|
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.*;
|
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import org.redkale.convert.bson.*;
|
import org.redkale.convert.bson.*;
|
||||||
@@ -38,36 +36,9 @@ public class Context {
|
|||||||
//ByteBuffer的容量,默认8K
|
//ByteBuffer的容量,默认8K
|
||||||
protected final int bufferCapacity;
|
protected final int bufferCapacity;
|
||||||
|
|
||||||
//ByteBuffer对象池
|
|
||||||
protected final ObjectPool<ByteBuffer> bufferPool;
|
|
||||||
|
|
||||||
//Response对象池
|
|
||||||
protected final ObjectPool<Response> responsePool;
|
|
||||||
|
|
||||||
//服务的根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,24 +51,41 @@ 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.maxconns, config.maxbody, config.charset, config.address, config.resourceFactory,
|
||||||
config.charset, config.address, config.resourceFactory, config.prepare,
|
config.prepare, config.aliveTimeoutSeconds, config.readTimeoutSeconds, config.writeTimeoutSeconds);
|
||||||
config.aliveTimeoutSeconds, config.readTimeoutSeconds, config.writeTimeoutSeconds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Context(long serverStartTime, Logger logger, ThreadPoolExecutor executor, SSLContext sslContext,
|
public Context(long serverStartTime, Logger logger, ThreadPoolExecutor executor, SSLContext sslContext,
|
||||||
int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool, final int maxconns,
|
int bufferCapacity, final int maxconns, final int maxbody, Charset charset, InetSocketAddress address,
|
||||||
final int maxbody, Charset charset, InetSocketAddress address, ResourceFactory resourceFactory,
|
ResourceFactory resourceFactory, PrepareServlet prepare, int aliveTimeoutSeconds, int readTimeoutSeconds, int writeTimeoutSeconds) {
|
||||||
final PrepareServlet prepare, final int aliveTimeoutSeconds, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
|
||||||
this.serverStartTime = serverStartTime;
|
this.serverStartTime = serverStartTime;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
this.bufferCapacity = bufferCapacity;
|
this.bufferCapacity = bufferCapacity;
|
||||||
this.bufferPool = bufferPool;
|
|
||||||
this.responsePool = responsePool;
|
|
||||||
this.maxconns = maxconns;
|
this.maxconns = maxconns;
|
||||||
this.maxbody = maxbody;
|
this.maxbody = maxbody;
|
||||||
this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset;
|
this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset;
|
||||||
@@ -147,33 +135,18 @@ public class Context {
|
|||||||
executor.execute(r);
|
executor.execute(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCorePoolSize() {
|
||||||
|
return executor.getCorePoolSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadFactory getThreadFactory() {
|
||||||
|
return executor.getThreadFactory();
|
||||||
|
}
|
||||||
|
|
||||||
public int getBufferCapacity() {
|
public int getBufferCapacity() {
|
||||||
return bufferCapacity;
|
return bufferCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Supplier<ByteBuffer> getBufferSupplier() {
|
|
||||||
return bufferPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Consumer<ByteBuffer> getBufferConsumer() {
|
|
||||||
return bufferPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer pollBuffer() {
|
|
||||||
return bufferPool.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerBuffer(ByteBuffer buffer) {
|
|
||||||
bufferPool.accept(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerBuffer(ByteBuffer... buffers) {
|
|
||||||
if (buffers == null) return;
|
|
||||||
for (ByteBuffer buffer : buffers) {
|
|
||||||
bufferPool.accept(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Logger getLogger() {
|
public Logger getLogger() {
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
@@ -212,12 +185,6 @@ public class Context {
|
|||||||
//ByteBuffer的容量,默认8K
|
//ByteBuffer的容量,默认8K
|
||||||
public int bufferCapacity;
|
public int bufferCapacity;
|
||||||
|
|
||||||
//ByteBuffer对象池
|
|
||||||
public ObjectPool<ByteBuffer> bufferPool;
|
|
||||||
|
|
||||||
//Response对象池
|
|
||||||
public ObjectPool<Response> responsePool;
|
|
||||||
|
|
||||||
//服务的根Servlet
|
//服务的根Servlet
|
||||||
public PrepareServlet prepare;
|
public PrepareServlet prepare;
|
||||||
|
|
||||||
|
|||||||
61
src/org/redkale/net/IOThread.java
Normal file
61
src/org/redkale/net/IOThread.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 协议处理的IO线程类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class IOThread extends Thread {
|
||||||
|
|
||||||
|
protected Thread localThread;
|
||||||
|
|
||||||
|
protected final ExecutorService executor;
|
||||||
|
|
||||||
|
protected ObjectPool<ByteBuffer> bufferPool;
|
||||||
|
|
||||||
|
public IOThread(ExecutorService executor, ObjectPool<ByteBuffer> bufferPool, Runnable runner) {
|
||||||
|
super(runner);
|
||||||
|
this.executor = executor;
|
||||||
|
this.bufferPool = bufferPool;
|
||||||
|
this.setDaemon(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runAsync(Runnable runner) {
|
||||||
|
executor.execute(runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutorService getExecutor() {
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectPool<ByteBuffer> getBufferPool() {
|
||||||
|
return bufferPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ package org.redkale.net;
|
|||||||
import java.io.IOException;
|
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.atomic.AtomicInteger;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
@@ -27,12 +27,15 @@ public class PrepareRunner implements Runnable {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
|
private final ObjectPool<Response> responsePool;
|
||||||
|
|
||||||
private ByteBuffer data;
|
private ByteBuffer data;
|
||||||
|
|
||||||
private Response response;
|
private Response response;
|
||||||
|
|
||||||
public PrepareRunner(Context context, AsyncConnection channel, ByteBuffer data, Response response) {
|
public PrepareRunner(Context context, ObjectPool<Response> responsePool, AsyncConnection channel, ByteBuffer data, Response response) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.responsePool = responsePool;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.response = response;
|
this.response = response;
|
||||||
@@ -40,29 +43,25 @@ public class PrepareRunner implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final boolean keepalive = response != null;
|
|
||||||
final PrepareServlet prepare = context.prepare;
|
|
||||||
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(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
new CompletionHandler<Integer, Void>() {
|
|
||||||
@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);
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(buffer);
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
@@ -75,39 +74,94 @@ 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);
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(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 (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 {
|
||||||
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(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 {
|
||||||
|
attachment.clear();
|
||||||
|
channel.setReadBuffer(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();
|
||||||
|
attachment.clear();
|
||||||
|
channel.setReadBuffer(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) {
|
||||||
@@ -115,7 +169,7 @@ public class PrepareRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Response pollResponse() {
|
protected Response pollResponse() {
|
||||||
return context.responsePool.get();
|
return responsePool.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Request pollRequest(Response response) {
|
protected Request pollRequest(Response response) {
|
||||||
@@ -126,19 +180,4 @@ public class PrepareRunner implements Runnable {
|
|||||||
return response.removeChannel();
|
return response.removeChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer(Request request) {
|
|
||||||
return request.pollReadBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer(Response response) {
|
|
||||||
return response.request.pollReadBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(Request request, ByteBuffer buffer) {
|
|
||||||
request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(Response response, ByteBuffer buffer) {
|
|
||||||
response.request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
final int rs = request.readHeader(buffer);
|
|
||||||
if (rs < 0) {
|
|
||||||
request.offerReadBuffer(buffer);
|
|
||||||
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();
|
request.prepare();
|
||||||
response.filter = this.headFilter;
|
response.filter = this.headFilter;
|
||||||
response.servlet = this;
|
response.servlet = this;
|
||||||
response.nextEvent();
|
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) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public abstract class ProtocolServer {
|
|||||||
|
|
||||||
public abstract <T> void setOption(SocketOption<T> name, T value) throws IOException;
|
public abstract <T> void setOption(SocketOption<T> name, T value) throws IOException;
|
||||||
|
|
||||||
public abstract void accept() throws IOException;
|
public abstract void accept(Server server) throws IOException;
|
||||||
|
|
||||||
public abstract void close() throws IOException;
|
public abstract void close() throws IOException;
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.redkale.convert.bson.BsonConvert;
|
import org.redkale.convert.bson.BsonConvert;
|
||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议请求对象
|
* 协议请求对象
|
||||||
@@ -23,6 +24,8 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected final C context;
|
protected final C context;
|
||||||
|
|
||||||
|
protected final ObjectPool<ByteBuffer> bufferPool;
|
||||||
|
|
||||||
protected final BsonConvert bsonConvert;
|
protected final BsonConvert bsonConvert;
|
||||||
|
|
||||||
protected final JsonConvert jsonConvert;
|
protected final JsonConvert jsonConvert;
|
||||||
@@ -37,8 +40,6 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected AsyncConnection channel;
|
protected AsyncConnection channel;
|
||||||
|
|
||||||
protected ByteBuffer readBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留;
|
* properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留;
|
||||||
* properties 通常存放需要永久绑定在request里的一些对象
|
* properties 通常存放需要永久绑定在request里的一些对象
|
||||||
@@ -47,9 +48,9 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected final Map<String, Object> attributes = new HashMap<>();
|
protected final Map<String, Object> attributes = new HashMap<>();
|
||||||
|
|
||||||
protected Request(C context) {
|
protected Request(C context, ObjectPool<ByteBuffer> bufferPool) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.readBuffer = context.pollBuffer();
|
this.bufferPool = bufferPool;
|
||||||
this.bsonConvert = context.getBsonConvert();
|
this.bsonConvert = context.getBsonConvert();
|
||||||
this.jsonConvert = context.getJsonConvert();
|
this.jsonConvert = context.getJsonConvert();
|
||||||
}
|
}
|
||||||
@@ -64,23 +65,6 @@ public abstract class Request<C extends Context> {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.readBuffer;
|
|
||||||
this.readBuffer = null;
|
|
||||||
if (buffer == null) buffer = context.pollBuffer();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(ByteBuffer buffer) {
|
|
||||||
if (buffer == null) return;
|
|
||||||
if (this.readBuffer == null) {
|
|
||||||
buffer.clear();
|
|
||||||
this.readBuffer = buffer;
|
|
||||||
} else {
|
|
||||||
context.offerBuffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议响应对象
|
* 协议响应对象
|
||||||
@@ -26,15 +27,13 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
protected final C context;
|
protected final C context;
|
||||||
|
|
||||||
|
protected final ObjectPool<Response> responsePool;
|
||||||
|
|
||||||
protected final R request;
|
protected final R request;
|
||||||
|
|
||||||
protected AsyncConnection channel;
|
protected AsyncConnection channel;
|
||||||
|
|
||||||
protected ByteBuffer writeHeadBuffer;
|
private volatile boolean inited = true;
|
||||||
|
|
||||||
protected ByteBuffer writeBodyBuffer;
|
|
||||||
|
|
||||||
private boolean inited = true;
|
|
||||||
|
|
||||||
protected Object output; //输出的结果对象
|
protected Object output; //输出的结果对象
|
||||||
|
|
||||||
@@ -44,8 +43,6 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
protected Servlet<C, R, ? extends Response<C, R>> servlet;
|
protected Servlet<C, R, ? extends Response<C, R>> servlet;
|
||||||
|
|
||||||
private Supplier<ByteBuffer> bodyBufferSupplier;
|
|
||||||
|
|
||||||
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
|
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -53,31 +50,21 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
if (attachment.hasRemaining()) {
|
if (attachment.hasRemaining()) {
|
||||||
channel.write(attachment, attachment, this);
|
channel.write(attachment, attachment, this);
|
||||||
} else {
|
} else {
|
||||||
offerResponseBuffer(attachment);
|
channel.offerBuffer(attachment);
|
||||||
|
ByteBuffer data = request.removeMoredata();
|
||||||
|
final boolean more = data != null && request.keepAlive;
|
||||||
|
request.more = more;
|
||||||
finish();
|
finish();
|
||||||
|
if (more) new PrepareRunner(context, responsePool, request.channel, null, Response.this).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerResponseBuffer(attachment);
|
channel.offerBuffer(attachment);
|
||||||
finish(true);
|
finish(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void offerResponseBuffer(ByteBuffer attachment) {
|
|
||||||
if (writeHeadBuffer == null) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachment)) {
|
|
||||||
writeHeadBuffer = attachment;
|
|
||||||
}
|
|
||||||
} else if (writeBodyBuffer == null) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachment)) {
|
|
||||||
writeBodyBuffer = attachment;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
context.offerBuffer(attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
|
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
|
||||||
@@ -94,70 +81,37 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
channel.write(attachments, index, attachments.length - index, attachments, this);
|
channel.write(attachments, index, attachments.length - index, attachments, this);
|
||||||
} else {
|
} else {
|
||||||
offerResponseBuffer(attachments);
|
for (ByteBuffer attachment : attachments) {
|
||||||
|
channel.offerBuffer(attachment);
|
||||||
|
}
|
||||||
|
ByteBuffer data = request.removeMoredata();
|
||||||
|
final boolean more = data != null && request.keepAlive;
|
||||||
|
request.more = more;
|
||||||
finish();
|
finish();
|
||||||
|
if (more) new PrepareRunner(context, responsePool, request.channel, null, Response.this).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, final ByteBuffer[] attachments) {
|
public void failed(Throwable exc, final ByteBuffer[] attachments) {
|
||||||
offerResponseBuffer(attachments);
|
for (ByteBuffer attachment : attachments) {
|
||||||
|
channel.offerBuffer(attachment);
|
||||||
|
}
|
||||||
finish(true);
|
finish(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void offerResponseBuffer(ByteBuffer[] attachments) {
|
|
||||||
int start = 0;
|
|
||||||
if (writeHeadBuffer == null && attachments.length > start) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachments[start])) {
|
|
||||||
writeHeadBuffer = attachments[start];
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (writeBodyBuffer == null && attachments.length > start) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachments[start])) {
|
|
||||||
writeBodyBuffer = attachments[start];
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = start; i < attachments.length; i++) {
|
|
||||||
context.offerBuffer(attachments[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
protected Response(C context, final R request) {
|
protected Response(C context, final R request, ObjectPool<Response> responsePool) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.request = request;
|
this.request = request;
|
||||||
this.writeHeadBuffer = context.pollBuffer();
|
this.responsePool = responsePool;
|
||||||
this.writeBodyBuffer = context.pollBuffer();
|
|
||||||
this.bodyBufferSupplier = () -> {
|
|
||||||
ByteBuffer buffer = writeBodyBuffer;
|
|
||||||
if (buffer == null) return context.pollBuffer();
|
|
||||||
writeBodyBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer pollWriteReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.writeHeadBuffer;
|
|
||||||
this.writeHeadBuffer = null;
|
|
||||||
if (buffer == null) buffer = context.pollBuffer();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer pollWriteBodyBuffer() {
|
|
||||||
ByteBuffer buffer = this.writeBodyBuffer;
|
|
||||||
this.writeBodyBuffer = null;
|
|
||||||
if (buffer == null) buffer = context.pollBuffer();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Supplier<ByteBuffer> getBodyBufferSupplier() {
|
|
||||||
return bodyBufferSupplier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void offerBuffer(ByteBuffer... buffers) {
|
protected void offerBuffer(ByteBuffer... buffers) {
|
||||||
context.offerBuffer(buffers);
|
for (ByteBuffer buffer : buffers) {
|
||||||
|
channel.offerBuffer(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AsyncConnection removeChannel() {
|
protected AsyncConnection removeChannel() {
|
||||||
@@ -257,19 +211,19 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
AsyncConnection conn = removeChannel();
|
AsyncConnection conn = removeChannel();
|
||||||
this.recycle();
|
this.recycle();
|
||||||
this.prepare();
|
this.prepare();
|
||||||
new PrepareRunner(context, conn, null, this).run();
|
new PrepareRunner(context, this.responsePool, conn, null, this).run();
|
||||||
} else {
|
} else {
|
||||||
channel.dispose();
|
channel.dispose();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.context.responsePool.accept(this);
|
this.responsePool.accept(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(final byte[] bs) {
|
public void finish(final byte[] bs) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
if (this.context.bufferCapacity == bs.length) {
|
if (this.context.bufferCapacity == bs.length) {
|
||||||
ByteBuffer buffer = this.context.pollBuffer();
|
ByteBuffer buffer = channel.bufferSupplier.get();
|
||||||
buffer.put(bs);
|
buffer.put(bs);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
this.finish(buffer);
|
this.finish(buffer);
|
||||||
@@ -280,33 +234,33 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
public void finish(ByteBuffer buffer) {
|
public void finish(ByteBuffer buffer) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
ByteBuffer data = this.request.removeMoredata();
|
|
||||||
final AsyncConnection conn = this.channel;
|
final AsyncConnection conn = this.channel;
|
||||||
final boolean more = data != null && this.request.keepAlive;
|
// ByteBuffer data = this.request.removeMoredata();
|
||||||
this.request.more = more;
|
// final boolean more = data != null && this.request.keepAlive;
|
||||||
|
// this.request.more = more;
|
||||||
conn.write(buffer, buffer, finishHandler);
|
conn.write(buffer, buffer, finishHandler);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(boolean kill, ByteBuffer buffer) {
|
public void finish(boolean kill, ByteBuffer buffer) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
if (kill) refuseAlive();
|
if (kill) refuseAlive();
|
||||||
ByteBuffer data = this.request.removeMoredata();
|
|
||||||
final AsyncConnection conn = this.channel;
|
final AsyncConnection conn = this.channel;
|
||||||
final boolean more = data != null && this.request.keepAlive;
|
// ByteBuffer data = this.request.removeMoredata();
|
||||||
this.request.more = more;
|
// final boolean more = data != null && this.request.keepAlive;
|
||||||
|
// this.request.more = more;
|
||||||
conn.write(buffer, buffer, finishHandler);
|
conn.write(buffer, buffer, finishHandler);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(ByteBuffer... buffers) {
|
public void finish(ByteBuffer... buffers) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
final AsyncConnection conn = this.channel;
|
final AsyncConnection conn = this.channel;
|
||||||
ByteBuffer data = this.request.removeMoredata();
|
// ByteBuffer data = this.request.removeMoredata();
|
||||||
final boolean more = data != null && this.request.keepAlive;
|
// final boolean more = data != null && this.request.keepAlive;
|
||||||
this.request.more = more;
|
// this.request.more = more;
|
||||||
conn.write(buffers, buffers, finishHandler2);
|
conn.write(buffers, buffers, finishHandler2);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(boolean kill, ByteBuffer... buffers) {
|
public void finish(boolean kill, ByteBuffer... buffers) {
|
||||||
@@ -317,7 +271,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
final boolean more = data != null && this.request.keepAlive;
|
final boolean more = data != null && this.request.keepAlive;
|
||||||
this.request.more = more;
|
this.request.more = more;
|
||||||
conn.write(buffers, buffers, finishHandler2);
|
conn.write(buffers, buffers, finishHandler2);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <A> void send(final ByteBuffer buffer, final A attachment, final CompletionHandler<Integer, A> handler) {
|
protected <A> void send(final ByteBuffer buffer, final A attachment, final CompletionHandler<Integer, A> handler) {
|
||||||
@@ -328,14 +282,14 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
if (buffer.hasRemaining()) {
|
if (buffer.hasRemaining()) {
|
||||||
channel.write(buffer, attachment, this);
|
channel.write(buffer, attachment, this);
|
||||||
} else {
|
} else {
|
||||||
context.offerBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
if (handler != null) handler.completed(result, attachment);
|
if (handler != null) handler.completed(result, attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
context.offerBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
if (handler != null) handler.failed(exc, attachment);
|
if (handler != null) handler.failed(exc, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +307,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
context.offerBuffer(buffers[i]);
|
channel.offerBuffer(buffers[i]);
|
||||||
}
|
}
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
channel.write(buffers, attachment, this);
|
channel.write(buffers, attachment, this);
|
||||||
@@ -367,7 +321,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
for (ByteBuffer buffer : buffers) {
|
for (ByteBuffer buffer : buffers) {
|
||||||
context.offerBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
}
|
}
|
||||||
if (handler != null) handler.failed(exc, attachment);
|
if (handler != null) handler.failed(exc, attachment);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ package org.redkale.net;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.text.*;
|
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.*;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
@@ -126,9 +127,9 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
this.writeTimeoutSeconds = config.getIntValue("writeTimeoutSeconds", 0);
|
this.writeTimeoutSeconds = config.getIntValue("writeTimeoutSeconds", 0);
|
||||||
this.backlog = parseLenth(config.getValue("backlog"), 8 * 1024);
|
this.backlog = parseLenth(config.getValue("backlog"), 8 * 1024);
|
||||||
this.maxbody = parseLenth(config.getValue("maxbody"), 64 * 1024);
|
this.maxbody = parseLenth(config.getValue("maxbody"), 64 * 1024);
|
||||||
int bufCapacity = parseLenth(config.getValue("bufferCapacity"), 32 * 1024);
|
int bufCapacity = parseLenth(config.getValue("bufferCapacity"), "UDP".equalsIgnoreCase(protocol) ? 1350 : 32 * 1024);
|
||||||
this.bufferCapacity = bufCapacity < 8 * 1024 ? 8 * 1024 : bufCapacity;
|
this.bufferCapacity = "UDP".equalsIgnoreCase(protocol) ? bufCapacity : (bufCapacity < 8 * 1024 ? 8 * 1024 : bufCapacity);
|
||||||
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 32);
|
this.threads = config.getIntValue("threads", Math.max(8, Runtime.getRuntime().availableProcessors() * 2));
|
||||||
this.bufferPoolSize = config.getIntValue("bufferPoolSize", this.threads * 4);
|
this.bufferPoolSize = config.getIntValue("bufferPoolSize", this.threads * 4);
|
||||||
this.responsePoolSize = config.getIntValue("responsePoolSize", this.threads * 2);
|
this.responsePoolSize = config.getIntValue("responsePoolSize", this.threads * 2);
|
||||||
this.name = config.getValue("name", "Server-" + protocol + "-" + this.address.getPort());
|
this.name = config.getValue("name", "Server-" + protocol + "-" + this.address.getPort());
|
||||||
@@ -152,7 +153,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
final String n = name;
|
final String n = name;
|
||||||
this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||||
Thread t = new WorkThread(executor, r);
|
Thread t = new WorkThread(executor, r);
|
||||||
t.setName(n + "-ServletThread-" + f.format(counter.incrementAndGet()));
|
t.setName("Redkale-" + n + "-ServletThread-" + f.format(counter.incrementAndGet()));
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -280,15 +281,96 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
this.serverChannel = ProtocolServer.create(this.protocol, context, this.serverClassLoader, config == null ? null : config.getValue("netimpl"));
|
this.serverChannel = ProtocolServer.create(this.protocol, context, this.serverClassLoader, config == null ? null : config.getValue("netimpl"));
|
||||||
this.serverChannel.open(config);
|
this.serverChannel.open(config);
|
||||||
serverChannel.bind(address, backlog);
|
serverChannel.bind(address, backlog);
|
||||||
serverChannel.accept();
|
serverChannel.accept(this);
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
postStart();
|
||||||
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol)) + " listen: " + address
|
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol)) + " listen: " + address
|
||||||
+ ", threads: " + threads + ", maxbody: " + formatLenth(context.maxbody) + ", bufferCapacity: " + formatLenth(bufferCapacity) + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
|
+ ", threads: " + threads + ", maxbody: " + formatLenth(context.maxbody) + ", bufferCapacity: " + formatLenth(bufferCapacity) + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
|
||||||
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
|
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void postStart() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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(this);
|
||||||
|
} 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();
|
||||||
|
|
||||||
|
//必须在 createContext()之后调用
|
||||||
|
protected abstract ObjectPool<ByteBuffer> createBufferPool(AtomicLong createCounter, AtomicLong cycleCounter, int bufferPoolSize);
|
||||||
|
|
||||||
|
//必须在 createContext()之后调用
|
||||||
|
protected abstract ObjectPool<Response> createResponsePool(AtomicLong createCounter, AtomicLong cycleCounter, int responsePoolSize);
|
||||||
|
|
||||||
|
//必须在 createResponsePool()之后调用
|
||||||
|
protected abstract Creator<Response> createResponseCreator(ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool);
|
||||||
|
|
||||||
public void shutdown() throws IOException {
|
public void shutdown() throws IOException {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
logger.info(this.getClass().getSimpleName() + "-" + this.protocol + " shutdowning");
|
logger.info(this.getClass().getSimpleName() + "-" + this.protocol + " shutdowning");
|
||||||
@@ -412,7 +494,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
classLoader.addURL(url);
|
classLoader.addURL(url);
|
||||||
}
|
}
|
||||||
List<URL> list = new ArrayList<>(set);
|
List<URL> list = new ArrayList<>(set);
|
||||||
Collections.sort(list, (URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));
|
list.sort((URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));
|
||||||
return list.toArray(new URL[list.size()]);
|
return list.toArray(new URL[list.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,13 @@ public abstract class Servlet<C extends Context, R extends Request<C>, P extends
|
|||||||
|
|
||||||
AnyValue _conf; //当前Servlet的配置
|
AnyValue _conf; //当前Servlet的配置
|
||||||
|
|
||||||
|
//Server执行start时运行此方法
|
||||||
public void init(C context, AnyValue config) {
|
public void init(C context, AnyValue config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void execute(R request, P response) throws IOException;
|
public abstract void execute(R request, P response) throws IOException;
|
||||||
|
|
||||||
|
//Server执行shutdown后运行此方法
|
||||||
public void destroy(C context, AnyValue config) {
|
public void destroy(C context, AnyValue config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.nio.channels.*;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,11 +36,12 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
|
|
||||||
private BlockingQueue<WriteEntry> writeQueue;
|
private BlockingQueue<WriteEntry> writeQueue;
|
||||||
|
|
||||||
public TcpAioAsyncConnection(final AsynchronousSocketChannel ch, SSLContext sslContext,
|
public TcpAioAsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer,
|
||||||
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds,
|
final AsynchronousSocketChannel ch, final SSLContext sslContext, final SocketAddress addr0,
|
||||||
|
final int readTimeoutSeconds, final int writeTimeoutSeconds,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
super(bufferSupplier, bufferConsumer, sslContext);
|
||||||
this.channel = ch;
|
this.channel = ch;
|
||||||
this.sslContext = sslContext;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
this.readTimeoutSeconds = readTimeoutSeconds;
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
||||||
SocketAddress addr = addr0;
|
SocketAddress addr = addr0;
|
||||||
@@ -91,24 +93,31 @@ 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
|
private <A> void nextWrite(Throwable exc, A attachment) {
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
this.readtime = System.currentTimeMillis();
|
|
||||||
channel.read(dst, timeout < 0 ? 0 : timeout, unit, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <A> void nextWrite(A attachment) {
|
|
||||||
BlockingQueue<WriteEntry> queue = this.writeQueue;
|
BlockingQueue<WriteEntry> queue = this.writeQueue;
|
||||||
|
if (queue != null && exc != null && !isOpen()) {
|
||||||
|
WriteEntry entry;
|
||||||
|
while ((entry = queue.poll()) != null) {
|
||||||
|
try {
|
||||||
|
entry.writeHandler.failed(exc, entry.writeAttachment);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
WriteEntry entry = queue == null ? null : queue.poll();
|
WriteEntry entry = queue == null ? null : queue.poll();
|
||||||
|
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
try {
|
try {
|
||||||
if (entry.writeOneBuffer == null) {
|
if (entry.writeOneBuffer == null) {
|
||||||
@@ -223,13 +232,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Future<Integer> read(ByteBuffer dst) {
|
public final int read(ByteBuffer dst) throws IOException {
|
||||||
return channel.read(dst);
|
try {
|
||||||
|
return channel.read(dst).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Future<Integer> write(ByteBuffer src) {
|
public final int write(ByteBuffer src) throws IOException {
|
||||||
return channel.write(src);
|
try {
|
||||||
|
return channel.write(src).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -300,18 +317,27 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
failed(e, attachment);
|
failed(e, attachment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.completed(writeCount, attachment);
|
writeHandler.completed(writeCount, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(null, attachment);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.completed(result.intValue(), attachment);
|
writeHandler.completed(result.intValue(), attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(null, attachment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.failed(exc, attachment);
|
writeHandler.failed(exc, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(exc, attachment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -338,14 +364,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
failed(e, attachment);
|
failed(e, attachment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.completed(result, attachment);
|
writeHandler.completed(result, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(null, attachment);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
nextWrite(attachment);
|
try {
|
||||||
writeHandler.failed(exc, attachment);
|
writeHandler.failed(exc, attachment);
|
||||||
|
} finally {
|
||||||
|
nextWrite(exc, attachment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ 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.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.redkale.util.AnyValue;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议底层Server
|
* 协议底层Server
|
||||||
@@ -70,7 +72,14 @@ public class TcpAioProtocolServer extends ProtocolServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept() throws IOException {
|
public void accept(Server server) throws IOException {
|
||||||
|
AtomicLong createBufferCounter = new AtomicLong();
|
||||||
|
AtomicLong cycleBufferCounter = new AtomicLong();
|
||||||
|
ObjectPool<ByteBuffer> bufferPool = server.createBufferPool(createBufferCounter, cycleBufferCounter, server.bufferPoolSize);
|
||||||
|
AtomicLong createResponseCounter = new AtomicLong();
|
||||||
|
AtomicLong cycleResponseCounter = new AtomicLong();
|
||||||
|
ObjectPool<Response> responsePool = server.createResponsePool(createResponseCounter, cycleResponseCounter, server.responsePoolSize);
|
||||||
|
responsePool.setCreator(server.createResponseCreator(bufferPool, responsePool));
|
||||||
final AsynchronousServerSocketChannel serchannel = this.serverChannel;
|
final AsynchronousServerSocketChannel serchannel = this.serverChannel;
|
||||||
serchannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
|
serchannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
|
||||||
|
|
||||||
@@ -92,13 +101,14 @@ 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(bufferPool, bufferPool, channel,
|
||||||
|
context.getSSLContext(), null, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
|
//context.runAsync(new PrepareRunner(context, responsePool, conn, null, null));
|
||||||
|
new PrepareRunner(context, responsePool, conn, null, null).run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
context.logger.log(Level.INFO, channel + " accept error", e);
|
||||||
}
|
}
|
||||||
AsyncConnection conn = new TcpAioAsyncConnection(channel, context.sslContext, null, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
|
||||||
conn.livingCounter = livingCounter;
|
|
||||||
conn.closedCounter = closedCounter;
|
|
||||||
context.runAsync(new PrepareRunner(context, conn, null, null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,240 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.redkale.net;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpBioAsyncConnection extends AsyncConnection {
|
|
||||||
|
|
||||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
|
||||||
|
|
||||||
private static Set<SocketOption<?>> defaultOptions() {
|
|
||||||
HashSet<SocketOption<?>> set = new HashSet<>(5);
|
|
||||||
set.add(StandardSocketOptions.SO_SNDBUF);
|
|
||||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
|
||||||
set.add(StandardSocketOptions.SO_KEEPALIVE);
|
|
||||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
|
||||||
set.add(StandardSocketOptions.TCP_NODELAY);
|
|
||||||
return Collections.unmodifiableSet(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readTimeoutSeconds;
|
|
||||||
|
|
||||||
private int writeTimeoutSeconds;
|
|
||||||
|
|
||||||
private final Socket socket;
|
|
||||||
|
|
||||||
private final ReadableByteChannel readChannel;
|
|
||||||
|
|
||||||
private final WritableByteChannel writeChannel;
|
|
||||||
|
|
||||||
private final SocketAddress remoteAddress;
|
|
||||||
|
|
||||||
public TcpBioAsyncConnection(final Socket socket, final SocketAddress addr0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
this.socket = socket;
|
|
||||||
ReadableByteChannel rc = null;
|
|
||||||
WritableByteChannel wc = null;
|
|
||||||
try {
|
|
||||||
socket.setSoTimeout(Math.max(readTimeoutSeconds0, writeTimeoutSeconds0));
|
|
||||||
rc = Channels.newChannel(socket.getInputStream());
|
|
||||||
wc = Channels.newChannel(socket.getOutputStream());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
this.readChannel = rc;
|
|
||||||
this.writeChannel = wc;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds0;
|
|
||||||
SocketAddress addr = addr0;
|
|
||||||
if (addr == null) {
|
|
||||||
try {
|
|
||||||
addr = socket.getRemoteSocketAddress();
|
|
||||||
} catch (Exception e) {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.remoteAddress = addr;
|
|
||||||
this.livingCounter = livingCounter;
|
|
||||||
this.closedCounter = closedCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTCP() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getRemoteAddress() {
|
|
||||||
return remoteAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getLocalAddress() {
|
|
||||||
return socket.getLocalSocketAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getReadTimeoutSeconds() {
|
|
||||||
return readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWriteTimeoutSeconds() {
|
|
||||||
return writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadTimeoutSeconds(int readTimeoutSeconds) {
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWriteTimeoutSeconds(int writeTimeoutSeconds) {
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownInput() {
|
|
||||||
try {
|
|
||||||
this.socket.shutdownInput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownOutput() {
|
|
||||||
try {
|
|
||||||
this.socket.shutdownOutput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean setOption(SocketOption<T> name, T value) {
|
|
||||||
try {
|
|
||||||
if (StandardSocketOptions.SO_REUSEADDR == name) {
|
|
||||||
this.socket.setReuseAddress((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_KEEPALIVE == name) {
|
|
||||||
this.socket.setKeepAlive((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.TCP_NODELAY == name) {
|
|
||||||
this.socket.setTcpNoDelay((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_RCVBUF == name) {
|
|
||||||
this.socket.setReceiveBufferSize((Integer) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_SNDBUF == name) {
|
|
||||||
this.socket.setSendBufferSize((Integer) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return defaultOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = 0;
|
|
||||||
for (int i = offset; i < offset + length; i++) {
|
|
||||||
rs += writeChannel.write(srcs[i]);
|
|
||||||
}
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = readChannel.read(dst);
|
|
||||||
this.readtime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
read(dst, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
|
||||||
try {
|
|
||||||
int rs = readChannel.read(dst);
|
|
||||||
this.readtime = System.currentTimeMillis();
|
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = writeChannel.write(src);
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
|
||||||
try {
|
|
||||||
int rs = writeChannel.write(src);
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
super.close();
|
|
||||||
this.socket.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !socket.isClosed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,366 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.redkale.net;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpNioAsyncConnection extends AsyncConnection {
|
|
||||||
|
|
||||||
protected int readTimeoutSeconds;
|
|
||||||
|
|
||||||
protected int writeTimeoutSeconds;
|
|
||||||
|
|
||||||
protected final Selector selector;
|
|
||||||
|
|
||||||
protected SelectionKey key;
|
|
||||||
|
|
||||||
protected final SocketChannel channel;
|
|
||||||
|
|
||||||
protected final SocketAddress remoteAddress;
|
|
||||||
|
|
||||||
ByteBuffer readBuffer;
|
|
||||||
|
|
||||||
Object readAttachment;
|
|
||||||
|
|
||||||
CompletionHandler readHandler;
|
|
||||||
|
|
||||||
ByteBuffer writeOneBuffer;
|
|
||||||
|
|
||||||
ByteBuffer[] writeBuffers;
|
|
||||||
|
|
||||||
int writingCount;
|
|
||||||
|
|
||||||
int writeOffset;
|
|
||||||
|
|
||||||
int writeLength;
|
|
||||||
|
|
||||||
Object writeAttachment;
|
|
||||||
|
|
||||||
CompletionHandler writeHandler;
|
|
||||||
|
|
||||||
public TcpNioAsyncConnection(final SocketChannel ch, SocketAddress addr0,
|
|
||||||
final Selector selector,
|
|
||||||
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
this.channel = ch;
|
|
||||||
this.selector = selector;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds0;
|
|
||||||
SocketAddress addr = addr0;
|
|
||||||
if (addr == null) {
|
|
||||||
try {
|
|
||||||
addr = ch.getRemoteAddress();
|
|
||||||
} catch (Exception e) {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.remoteAddress = addr;
|
|
||||||
this.livingCounter = livingCounter;
|
|
||||||
this.closedCounter = closedCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadTimeoutSeconds(int readTimeoutSeconds) {
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWriteTimeoutSeconds(int writeTimeoutSeconds) {
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getReadTimeoutSeconds() {
|
|
||||||
return this.readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWriteTimeoutSeconds() {
|
|
||||||
return this.writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final SocketAddress getRemoteAddress() {
|
|
||||||
return remoteAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getLocalAddress() {
|
|
||||||
try {
|
|
||||||
return channel.getLocalAddress();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownInput() {
|
|
||||||
try {
|
|
||||||
this.channel.shutdownInput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownOutput() {
|
|
||||||
try {
|
|
||||||
this.channel.shutdownOutput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean setOption(SocketOption<T> name, T value) {
|
|
||||||
try {
|
|
||||||
this.channel.setOption(name, value);
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return this.channel.supportedOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletionHandler removeReadHandler() {
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readHandler = null;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer removeReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.readBuffer;
|
|
||||||
this.readBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object removeReadAttachment() {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
this.readAttachment = null;
|
|
||||||
return attach;
|
|
||||||
}
|
|
||||||
|
|
||||||
void completeRead(int rs) {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readBuffer = null;
|
|
||||||
this.readAttachment = null;
|
|
||||||
this.readHandler = null;
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
void faileRead(Throwable t) {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readBuffer = null;
|
|
||||||
this.readAttachment = null;
|
|
||||||
this.readHandler = null;
|
|
||||||
handler.failed(t, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletionHandler removeWriteHandler() {
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeHandler = null;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer removeWriteOneBuffer() {
|
|
||||||
ByteBuffer buffer = this.writeOneBuffer;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer[] removeWriteBuffers() {
|
|
||||||
ByteBuffer[] buffers = this.writeBuffers;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
return buffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWritingCount() {
|
|
||||||
int rs = this.writingCount;
|
|
||||||
this.writingCount = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWriteOffset() {
|
|
||||||
int rs = this.writeOffset;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWriteLength() {
|
|
||||||
int rs = this.writeLength;
|
|
||||||
this.writeLength = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object removeWriteAttachment() {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
return attach;
|
|
||||||
}
|
|
||||||
|
|
||||||
void completeWrite(int rs) {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
this.writeLength = 0;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
this.writeHandler = null;
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
void faileWrite(Throwable t) {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
this.writeLength = 0;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
this.writeHandler = null;
|
|
||||||
handler.failed(t, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.readHandler != null) throw new RuntimeException("pending read");
|
|
||||||
try {
|
|
||||||
this.readBuffer = dst;
|
|
||||||
this.readAttachment = attachment;
|
|
||||||
this.readHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_READ);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_READ);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileRead(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
read(dst, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
|
||||||
CompletableFuture future = new CompletableFuture();
|
|
||||||
read(dst, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
@Override
|
|
||||||
public void completed(Integer result, Void attachment) {
|
|
||||||
future.complete(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(Throwable exc, Void attachment) {
|
|
||||||
future.completeExceptionally(exc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.writeHandler != null) throw new RuntimeException("pending write");
|
|
||||||
try {
|
|
||||||
this.writeBuffers = srcs;
|
|
||||||
this.writeOffset = offset;
|
|
||||||
this.writeLength = length;
|
|
||||||
this.writingCount = 0;
|
|
||||||
this.writeAttachment = attachment;
|
|
||||||
this.writeHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_WRITE);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileWrite(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.writeHandler != null) throw new RuntimeException("pending write");
|
|
||||||
try {
|
|
||||||
this.writeOneBuffer = src;
|
|
||||||
this.writingCount = 0;
|
|
||||||
this.writeAttachment = attachment;
|
|
||||||
this.writeHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_WRITE);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileWrite(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
|
||||||
CompletableFuture future = new CompletableFuture();
|
|
||||||
write(src, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
@Override
|
|
||||||
public void completed(Integer result, Void attachment) {
|
|
||||||
future.complete(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(Throwable exc, Void attachment) {
|
|
||||||
future.completeExceptionally(exc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void close() throws IOException {
|
|
||||||
super.close();
|
|
||||||
channel.close();
|
|
||||||
key.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isOpen() {
|
|
||||||
return channel.isOpen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isTCP() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,370 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.redkale.net;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import org.redkale.util.AnyValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 协议底层Server
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpNioProtocolServer extends ProtocolServer {
|
|
||||||
|
|
||||||
private Selector acceptSelector;
|
|
||||||
|
|
||||||
private ServerSocketChannel serverChannel;
|
|
||||||
|
|
||||||
private NioThreadWorker[] workers;
|
|
||||||
|
|
||||||
private NioThreadWorker currWorker;
|
|
||||||
|
|
||||||
private boolean running;
|
|
||||||
|
|
||||||
public TcpNioProtocolServer(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void open(AnyValue config) throws IOException {
|
|
||||||
acceptSelector = Selector.open();
|
|
||||||
this.serverChannel = ServerSocketChannel.open();
|
|
||||||
serverChannel.configureBlocking(false);
|
|
||||||
ServerSocket socket = serverChannel.socket();
|
|
||||||
socket.setReceiveBufferSize(16 * 1024);
|
|
||||||
socket.setReuseAddress(true);
|
|
||||||
|
|
||||||
final Set<SocketOption<?>> options = this.serverChannel.supportedOptions();
|
|
||||||
if (options.contains(StandardSocketOptions.TCP_NODELAY)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_KEEPALIVE)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_REUSEADDR)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_RCVBUF)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_SNDBUF)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bind(SocketAddress local, int backlog) throws IOException {
|
|
||||||
this.serverChannel.bind(local, backlog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return this.serverChannel.supportedOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
|
|
||||||
this.serverChannel.setOption(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept() throws IOException {
|
|
||||||
this.serverChannel.register(acceptSelector, SelectionKey.OP_ACCEPT);
|
|
||||||
this.running = true;
|
|
||||||
this.workers = new NioThreadWorker[Runtime.getRuntime().availableProcessors()];
|
|
||||||
final CountDownLatch wkcdl = new CountDownLatch(workers.length);
|
|
||||||
for (int i = 0; i < workers.length; i++) {
|
|
||||||
workers[i] = new NioThreadWorker(wkcdl, i + 1, workers.length);
|
|
||||||
workers[i].setDaemon(true);
|
|
||||||
workers[i].start();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < workers.length - 1; i++) { //构成环形
|
|
||||||
workers[i].next = workers[i + 1];
|
|
||||||
}
|
|
||||||
workers[workers.length - 1].next = workers[0];
|
|
||||||
currWorker = workers[0];
|
|
||||||
try {
|
|
||||||
wkcdl.await(3, TimeUnit.SECONDS);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
final CountDownLatch cdl = new CountDownLatch(1);
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
cdl.countDown();
|
|
||||||
while (running) {
|
|
||||||
try {
|
|
||||||
acceptSelector.select();
|
|
||||||
Set<SelectionKey> selectedKeys = acceptSelector.selectedKeys();
|
|
||||||
synchronized (selectedKeys) {
|
|
||||||
Iterator<?> iter = selectedKeys.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
SelectionKey key = (SelectionKey) iter.next();
|
|
||||||
iter.remove();
|
|
||||||
if (key.isAcceptable()) {
|
|
||||||
try {
|
|
||||||
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
|
|
||||||
createCounter.incrementAndGet();
|
|
||||||
livingCounter.incrementAndGet();
|
|
||||||
currWorker.addChannel(channel);
|
|
||||||
currWorker = currWorker.next;
|
|
||||||
} catch (IOException io) {
|
|
||||||
io.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
try {
|
|
||||||
cdl.await(3, TimeUnit.SECONDS);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
if (!this.running) return;
|
|
||||||
serverChannel.close();
|
|
||||||
acceptSelector.close();
|
|
||||||
for (NioThreadWorker worker : workers) {
|
|
||||||
worker.interrupt();
|
|
||||||
}
|
|
||||||
this.running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class NioThreadWorker extends Thread {
|
|
||||||
|
|
||||||
final Selector selector;
|
|
||||||
|
|
||||||
final CountDownLatch cdl;
|
|
||||||
|
|
||||||
private final Queue<TcpNioAsyncConnection> connected;
|
|
||||||
|
|
||||||
private final CopyOnWriteArrayList<TcpNioAsyncConnection> done;
|
|
||||||
|
|
||||||
protected volatile Thread ownerThread;
|
|
||||||
|
|
||||||
NioThreadWorker next;
|
|
||||||
|
|
||||||
public NioThreadWorker(final CountDownLatch cdl, int idx, int count) {
|
|
||||||
this.cdl = cdl;
|
|
||||||
String idxstr = "000000" + idx;
|
|
||||||
this.setName("NioThreadWorker:" + context.getServerAddress().getPort() + "-" + idxstr.substring(idxstr.length() - ("" + count).length()));
|
|
||||||
try {
|
|
||||||
this.selector = Selector.open();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
this.connected = new ArrayBlockingQueue<>(1000000);
|
|
||||||
this.done = new CopyOnWriteArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addChannel(SocketChannel channel) throws IOException {
|
|
||||||
TcpNioAsyncConnection conn = new TcpNioAsyncConnection(channel, null, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
|
||||||
return connected.add(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void processConnected() {
|
|
||||||
TcpNioAsyncConnection schannel;
|
|
||||||
try {
|
|
||||||
while ((schannel = connected.poll()) != null) {
|
|
||||||
SocketChannel channel = schannel.channel;
|
|
||||||
channel.configureBlocking(false);
|
|
||||||
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
|
||||||
channel.register(selector, SelectionKey.OP_READ).attach(schannel);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
synchronized (done) {
|
|
||||||
for (TcpNioAsyncConnection conn : done) {
|
|
||||||
if (conn.key != null && conn.key.isValid()) {
|
|
||||||
conn.key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSameThread() {
|
|
||||||
return this.ownerThread == Thread.currentThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
this.ownerThread = Thread.currentThread();
|
|
||||||
if (cdl != null) cdl.countDown();
|
|
||||||
while (running) {
|
|
||||||
processConnected();
|
|
||||||
try {
|
|
||||||
selector.select(50);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Set<SelectionKey> selectedKeys = selector.selectedKeys();
|
|
||||||
synchronized (selectedKeys) {
|
|
||||||
Iterator<?> iter = selectedKeys.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
SelectionKey key = (SelectionKey) iter.next();
|
|
||||||
iter.remove();
|
|
||||||
processKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processKey(SelectionKey key) {
|
|
||||||
if (key == null || !key.isValid()) return;
|
|
||||||
SocketChannel socket = (SocketChannel) key.channel();
|
|
||||||
TcpNioAsyncConnection conn = (TcpNioAsyncConnection) key.attachment();
|
|
||||||
if (!socket.isOpen()) {
|
|
||||||
if (conn == null) {
|
|
||||||
key.cancel();
|
|
||||||
} else {
|
|
||||||
conn.dispose();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (conn == null) return;
|
|
||||||
if (key.isReadable()) {
|
|
||||||
if (conn.readHandler != null) readOP(key, socket, conn);
|
|
||||||
} else if (key.isWritable()) {
|
|
||||||
if (conn.writeHandler != null) writeOP(key, socket, conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeOP(SelectionKey key) {
|
|
||||||
if (key == null) return;
|
|
||||||
TcpNioAsyncConnection conn = (TcpNioAsyncConnection) key.attachment();
|
|
||||||
try {
|
|
||||||
if (key.isValid()) {
|
|
||||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
|
||||||
socketChannel.close();
|
|
||||||
key.attach(null);
|
|
||||||
key.cancel();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
conn.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readOP(SelectionKey key, SocketChannel socket, TcpNioAsyncConnection conn) {
|
|
||||||
final CompletionHandler handler = conn.removeReadHandler();
|
|
||||||
final ByteBuffer buffer = conn.removeReadBuffer();
|
|
||||||
final Object attach = conn.removeReadAttachment();
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler);
|
|
||||||
if (handler == null || buffer == null) return;
|
|
||||||
try {
|
|
||||||
final int rs = socket.read(buffer);
|
|
||||||
{ //测试
|
|
||||||
buffer.flip();
|
|
||||||
byte[] bs = new byte[buffer.remaining()];
|
|
||||||
buffer.get(bs);
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler + "-------读内容: " + new String(bs));
|
|
||||||
}
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler + "-------read: " + rs);
|
|
||||||
context.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
handler.failed(e, attach);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
context.runAsync(() -> handler.failed(t, attach));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeOP(SelectionKey key, SocketChannel socket, TcpNioAsyncConnection conn) {
|
|
||||||
final CompletionHandler handler = conn.writeHandler;
|
|
||||||
final ByteBuffer oneBuffer = conn.removeWriteOneBuffer();
|
|
||||||
final ByteBuffer[] buffers = conn.removeWriteBuffers();
|
|
||||||
final Object attach = conn.removeWriteAttachment();
|
|
||||||
final int writingCount = conn.removeWritingCount();
|
|
||||||
final int writeOffset = conn.removeWriteOffset();
|
|
||||||
final int writeLength = conn.removeWriteLength();
|
|
||||||
if (handler == null || (oneBuffer == null && buffers == null)) return;
|
|
||||||
//System.out.println(conn + "------buffers:" + Arrays.toString(buffers) + "---onebuf:" + oneBuffer + "-------handler:" + handler);
|
|
||||||
try {
|
|
||||||
int rs = 0;
|
|
||||||
if (oneBuffer == null) {
|
|
||||||
int offset = writeOffset;
|
|
||||||
int length = writeLength;
|
|
||||||
rs = (int) socket.write(buffers, offset, length);
|
|
||||||
boolean over = true;
|
|
||||||
int end = offset + length;
|
|
||||||
for (int i = offset; i < end; i++) {
|
|
||||||
if (buffers[i].hasRemaining()) {
|
|
||||||
over = false;
|
|
||||||
length -= i - offset;
|
|
||||||
offset = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!over) {
|
|
||||||
conn.writingCount += rs;
|
|
||||||
conn.writeHandler = handler;
|
|
||||||
conn.writeAttachment = attach;
|
|
||||||
conn.writeBuffers = buffers;
|
|
||||||
conn.writeOffset = offset;
|
|
||||||
conn.writeLength = length;
|
|
||||||
key.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE);
|
|
||||||
key.selector().wakeup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rs = socket.write(oneBuffer);
|
|
||||||
if (oneBuffer.hasRemaining()) {
|
|
||||||
conn.writingCount += rs;
|
|
||||||
conn.writeHandler = handler;
|
|
||||||
conn.writeAttachment = attach;
|
|
||||||
conn.writeOneBuffer = oneBuffer;
|
|
||||||
key.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE);
|
|
||||||
key.selector().wakeup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
conn.removeWriteHandler();
|
|
||||||
key.interestOps(SelectionKey.OP_READ); //OP_CONNECT
|
|
||||||
final int rs0 = rs + writingCount;
|
|
||||||
//System.out.println(conn + "------buffers:" + Arrays.toString(buffers) + "---onebuf:" + oneBuffer + "-------handler:" + handler + "-------write: " + rs);
|
|
||||||
context.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
handler.completed(rs0, attach);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
handler.failed(e, attach);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
context.runAsync(() -> handler.failed(t, attach));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -215,12 +215,12 @@ public final class Transport {
|
|||||||
DatagramChannel channel = DatagramChannel.open();
|
DatagramChannel channel = DatagramChannel.open();
|
||||||
channel.configureBlocking(true);
|
channel.configureBlocking(true);
|
||||||
channel.connect(udpaddr);
|
channel.connect(udpaddr);
|
||||||
return CompletableFuture.completedFuture(AsyncConnection.create(channel, udpaddr, true, factory.readTimeoutSeconds, factory.writeTimeoutSeconds));
|
return CompletableFuture.completedFuture(AsyncConnection.create(bufferPool, channel, sslContext, udpaddr, true, factory.readTimeoutSeconds, factory.writeTimeoutSeconds));
|
||||||
}
|
}
|
||||||
if (!rand) { //指定地址
|
if (!rand) { //指定地址
|
||||||
TransportNode node = findTransportNode(addr);
|
TransportNode node = findTransportNode(addr);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return AsyncConnection.createTCP(group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
return AsyncConnection.createTCP(bufferPool, group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
final BlockingQueue<AsyncConnection> queue = node.conns;
|
final BlockingQueue<AsyncConnection> queue = node.conns;
|
||||||
if (!queue.isEmpty()) {
|
if (!queue.isEmpty()) {
|
||||||
@@ -233,7 +233,7 @@ public final class Transport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AsyncConnection.createTCP(group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
return AsyncConnection.createTCP(bufferPool, group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------随机取地址------------------------
|
//---------------------随机取地址------------------------
|
||||||
@@ -266,7 +266,7 @@ public final class Transport {
|
|||||||
@Override
|
@Override
|
||||||
public void completed(Void result, TransportNode attachment) {
|
public void completed(Void result, TransportNode attachment) {
|
||||||
attachment.disabletime = 0;
|
attachment.disabletime = 0;
|
||||||
AsyncConnection asyncConn = AsyncConnection.create(channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
AsyncConnection asyncConn = AsyncConnection.create(bufferPool, channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
||||||
} else {
|
} else {
|
||||||
@@ -319,7 +319,7 @@ public final class Transport {
|
|||||||
public void completed(Void result, TransportNode attachment) {
|
public void completed(Void result, TransportNode attachment) {
|
||||||
try {
|
try {
|
||||||
attachment.disabletime = 0;
|
attachment.disabletime = 0;
|
||||||
AsyncConnection asyncConn = AsyncConnection.create(channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
AsyncConnection asyncConn = AsyncConnection.create(bufferPool, channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
||||||
} else {
|
} else {
|
||||||
@@ -371,18 +371,19 @@ public final class Transport {
|
|||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
if (handler != null) handler.completed(result, att);
|
if (handler != null) handler.completed(result, att);
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(false, conn);
|
offerConnection(false, conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(true, conn);
|
offerConnection(true, conn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -391,7 +392,7 @@ public final class Transport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(true, conn);
|
offerConnection(true, conn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public class TransportFactory {
|
|||||||
if (this.checkinterval < 2) this.checkinterval = 2;
|
if (this.checkinterval < 2) this.checkinterval = 2;
|
||||||
}
|
}
|
||||||
this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
|
this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
|
||||||
final Thread t = new Thread(r, this.getClass().getSimpleName() + "-TransportFactoryTask-Thread");
|
final Thread t = new Thread(r, "Redkale-" + this.getClass().getSimpleName() + "-Schedule-Thread");
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
@@ -162,7 +162,7 @@ public class TransportFactory {
|
|||||||
ExecutorService transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
ExecutorService transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
AsynchronousChannelGroup transportGroup = null;
|
AsynchronousChannelGroup transportGroup = null;
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ import java.net.*;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
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 +33,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 +130,22 @@ 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 int read(ByteBuffer dst) throws IOException {
|
||||||
read(dst, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
|
||||||
try {
|
|
||||||
int rs = channel.read(dst);
|
int rs = channel.read(dst);
|
||||||
this.readtime = System.currentTimeMillis();
|
this.readtime = System.currentTimeMillis();
|
||||||
return CompletableFuture.completedFuture(rs);
|
return rs;
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -165,14 +160,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 CompletableFuture.completedFuture(rs);
|
return rs;
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.channels.DatagramChannel;
|
import java.nio.channels.DatagramChannel;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import org.redkale.util.AnyValue;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议底层Server
|
* 协议底层Server
|
||||||
@@ -70,7 +71,14 @@ public class UdpBioProtocolServer extends ProtocolServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept() throws IOException {
|
public void accept(Server server) throws IOException {
|
||||||
|
AtomicLong createBufferCounter = new AtomicLong();
|
||||||
|
AtomicLong cycleBufferCounter = new AtomicLong();
|
||||||
|
ObjectPool<ByteBuffer> bufferPool = server.createBufferPool(createBufferCounter, cycleBufferCounter, server.bufferPoolSize);
|
||||||
|
AtomicLong createResponseCounter = new AtomicLong();
|
||||||
|
AtomicLong cycleResponseCounter = new AtomicLong();
|
||||||
|
ObjectPool<Response> responsePool = server.createResponsePool(createResponseCounter, cycleResponseCounter, server.responsePoolSize);
|
||||||
|
responsePool.setCreator(server.createResponseCreator(bufferPool, responsePool));
|
||||||
final DatagramChannel serchannel = this.serverChannel;
|
final DatagramChannel serchannel = this.serverChannel;
|
||||||
final int readTimeoutSeconds = this.context.readTimeoutSeconds;
|
final int readTimeoutSeconds = this.context.readTimeoutSeconds;
|
||||||
final int writeTimeoutSeconds = this.context.writeTimeoutSeconds;
|
final int writeTimeoutSeconds = this.context.writeTimeoutSeconds;
|
||||||
@@ -81,14 +89,15 @@ public class UdpBioProtocolServer extends ProtocolServer {
|
|||||||
public void run() {
|
public void run() {
|
||||||
cdl.countDown();
|
cdl.countDown();
|
||||||
while (running) {
|
while (running) {
|
||||||
final ByteBuffer buffer = context.pollBuffer();
|
final ByteBuffer buffer = bufferPool.get();
|
||||||
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(bufferPool, bufferPool, serchannel,
|
||||||
context.runAsync(new PrepareRunner(context, conn, buffer, null));
|
context.getSSLContext(), address, false, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
|
context.runAsync(new PrepareRunner(context, responsePool, conn, buffer, null));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
context.offerBuffer(buffer);
|
bufferPool.accept(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import java.util.concurrent.*;
|
|||||||
*/
|
*/
|
||||||
public class WorkThread extends Thread {
|
public class WorkThread extends Thread {
|
||||||
|
|
||||||
|
protected Thread localThread;
|
||||||
|
|
||||||
private final ExecutorService executor;
|
private final ExecutorService executor;
|
||||||
|
|
||||||
public WorkThread(ExecutorService executor, Runnable runner) {
|
public WorkThread(ExecutorService executor, Runnable runner) {
|
||||||
@@ -32,4 +34,19 @@ public class WorkThread extends Thread {
|
|||||||
public ExecutorService getExecutor() {
|
public ExecutorService getExecutor() {
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
this.localThread = Thread.currentThread();
|
||||||
|
super.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inSameThread() {
|
||||||
|
return this.localThread == Thread.currentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inSameThread(Thread thread) {
|
||||||
|
return this.localThread == thread;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.net.http;
|
package org.redkale.net.http;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import org.redkale.asm.MethodDebugVisitor;
|
import org.redkale.asm.MethodDebugVisitor;
|
||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
|
||||||
import org.redkale.asm.*;
|
import org.redkale.asm.*;
|
||||||
import static org.redkale.asm.Opcodes.*;
|
import static org.redkale.asm.Opcodes.*;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
@@ -30,6 +28,8 @@ public class HttpContext extends Context {
|
|||||||
|
|
||||||
protected final ConcurrentHashMap<Class, Creator> asyncHandlerCreators = new ConcurrentHashMap<>();
|
protected final ConcurrentHashMap<Class, Creator> asyncHandlerCreators = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
protected String remoteAddrHeader;
|
||||||
|
|
||||||
public HttpContext(HttpContextConfig config) {
|
public HttpContext(HttpContextConfig config) {
|
||||||
super(config);
|
super(config);
|
||||||
random.setSeed(Math.abs(System.nanoTime()));
|
random.setSeed(Math.abs(System.nanoTime()));
|
||||||
@@ -45,25 +45,6 @@ public class HttpContext extends Context {
|
|||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ObjectPool<Response> getResponsePool() {
|
|
||||||
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);
|
||||||
@@ -179,5 +160,6 @@ public class HttpContext extends Context {
|
|||||||
|
|
||||||
public static class HttpContextConfig extends ContextConfig {
|
public static class HttpContextConfig extends ContextConfig {
|
||||||
|
|
||||||
|
public String remoteAddrHeader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.redkale.net.http;
|
package org.redkale.net.http;
|
||||||
|
|
||||||
import org.redkale.net.Filter;
|
import org.redkale.net.Filter;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP 过滤器 <br>
|
* HTTP 过滤器 <br>
|
||||||
@@ -17,4 +18,7 @@ import org.redkale.net.Filter;
|
|||||||
*/
|
*/
|
||||||
public abstract class HttpFilter extends Filter<HttpContext, HttpRequest, HttpResponse> {
|
public abstract class HttpFilter extends Filter<HttpContext, HttpRequest, HttpResponse> {
|
||||||
|
|
||||||
|
//Server执行start后运行此方法
|
||||||
|
public void postStart(HttpContext context, AnyValue config) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -253,7 +254,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
logger.log(Level.WARNING, "init HttpRender(" + renderType + ") error", e);
|
logger.log(Level.WARNING, "init HttpRender(" + renderType + ") error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(renders, (o1, o2) -> o1.getType().isAssignableFrom(o2.getType()) ? 1 : -1);
|
renders.sort((o1, o2) -> o1.getType().isAssignableFrom(o2.getType()) ? 1 : -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,6 +402,21 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
return this.resourceHttpServlet;
|
return this.resourceHttpServlet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void postStart(HttpContext context, AnyValue config) {
|
||||||
|
List filters = getFilters();
|
||||||
|
synchronized (filters) {
|
||||||
|
if (!filters.isEmpty()) {
|
||||||
|
for (Object filter : filters) {
|
||||||
|
((HttpFilter) filter).postStart(context, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.resourceHttpServlet.postStart(context, config);
|
||||||
|
getServlets().forEach(s -> {
|
||||||
|
s.postStart(context, getServletConf(s));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy(HttpContext context, AnyValue config) {
|
public void destroy(HttpContext context, AnyValue config) {
|
||||||
super.destroy(context, config); //必须要执行
|
super.destroy(context, config); //必须要执行
|
||||||
|
|||||||
@@ -6,11 +6,14 @@
|
|||||||
package org.redkale.net.http;
|
package org.redkale.net.http;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
@@ -40,6 +43,8 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
|
|
||||||
protected String requestURI;
|
protected String requestURI;
|
||||||
|
|
||||||
|
private byte[] queryBytes;
|
||||||
|
|
||||||
private long contentLength = -1;
|
private long contentLength = -1;
|
||||||
|
|
||||||
private String contentType;
|
private String contentType;
|
||||||
@@ -69,15 +74,17 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
|
|
||||||
protected int actionid;
|
protected int actionid;
|
||||||
|
|
||||||
|
protected Annotation[] annotations;
|
||||||
|
|
||||||
protected Object currentUser;
|
protected Object currentUser;
|
||||||
|
|
||||||
private final String remoteAddrHeader;
|
private final String remoteAddrHeader;
|
||||||
|
|
||||||
Object attachment; //仅供HttpServlet传递Entry使用
|
Object attachment; //仅供HttpServlet传递Entry使用
|
||||||
|
|
||||||
public HttpRequest(HttpContext context, String remoteAddrHeader) {
|
public HttpRequest(HttpContext context, ObjectPool<ByteBuffer> bufferPool) {
|
||||||
super(context);
|
super(context, bufferPool);
|
||||||
this.remoteAddrHeader = remoteAddrHeader;
|
this.remoteAddrHeader = context.remoteAddrHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isWebSocket() {
|
protected boolean isWebSocket() {
|
||||||
@@ -116,9 +123,15 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
int qst = array.find(index, offset, (byte) '?');
|
int qst = array.find(index, offset, (byte) '?');
|
||||||
if (qst > 0) {
|
if (qst > 0) {
|
||||||
this.requestURI = array.toDecodeString(index, qst - index, charset).trim();
|
this.requestURI = array.toDecodeString(index, qst - index, charset).trim();
|
||||||
|
this.queryBytes = array.getBytes(qst + 1, offset - qst - 1);
|
||||||
|
try {
|
||||||
addParameter(array, qst + 1, offset - qst - 1);
|
addParameter(array, qst + 1, offset - qst - 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.context.getLogger().log(Level.WARNING, "HttpRequest.addParameter error: " + array.toString(), e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.requestURI = array.toDecodeString(index, offset - index, charset).trim();
|
this.requestURI = array.toDecodeString(index, offset - index, charset).trim();
|
||||||
|
this.queryBytes = new byte[0];
|
||||||
}
|
}
|
||||||
index = ++offset;
|
index = ++offset;
|
||||||
this.protocol = array.toString(index, array.size() - index, charset).trim();
|
this.protocol = array.toString(index, array.size() - index, charset).trim();
|
||||||
@@ -197,7 +210,9 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
|
|
||||||
private void parseBody() {
|
private void parseBody() {
|
||||||
if (this.boundary || bodyparsed) return;
|
if (this.boundary || bodyparsed) return;
|
||||||
|
if (this.contentType != null && this.contentType.toLowerCase().contains("x-www-form-urlencoded")) {
|
||||||
addParameter(array, 0, array.size());
|
addParameter(array, 0, array.size());
|
||||||
|
}
|
||||||
bodyparsed = true;
|
bodyparsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +313,55 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
return this.actionid;
|
return this.actionid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前操作Method上的注解集合
|
||||||
|
*
|
||||||
|
* @return Annotation[]
|
||||||
|
*/
|
||||||
|
public Annotation[] getAnnotations() {
|
||||||
|
if (this.annotations == null) return new Annotation[0];
|
||||||
|
Annotation[] newanns = new Annotation[this.annotations.length];
|
||||||
|
System.arraycopy(this.annotations, 0, newanns, 0, newanns.length);
|
||||||
|
return newanns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前操作Method上的注解
|
||||||
|
*
|
||||||
|
* @param <T> 注解泛型
|
||||||
|
* @param annotationClass 注解类型
|
||||||
|
*
|
||||||
|
* @return Annotation
|
||||||
|
*/
|
||||||
|
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
|
||||||
|
if (this.annotations == null) return null;
|
||||||
|
for (Annotation ann : this.annotations) {
|
||||||
|
if (ann.getClass() == annotationClass) return (T) ann;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前操作Method上的注解集合
|
||||||
|
*
|
||||||
|
* @param <T> 注解泛型
|
||||||
|
* @param annotationClass 注解类型
|
||||||
|
*
|
||||||
|
* @return Annotation[]
|
||||||
|
*/
|
||||||
|
public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
|
||||||
|
if (this.annotations == null) return (T[]) Array.newInstance(annotationClass, 0);
|
||||||
|
T[] news = (T[]) Array.newInstance(annotationClass, this.annotations.length);
|
||||||
|
int index = 0;
|
||||||
|
for (Annotation ann : this.annotations) {
|
||||||
|
if (ann.getClass() == annotationClass) {
|
||||||
|
news[index++] = (T) ann;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index < 1) return (T[]) Array.newInstance(annotationClass, 0);
|
||||||
|
return Arrays.copyOf(news, index);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取客户端地址IP
|
* 获取客户端地址IP
|
||||||
*
|
*
|
||||||
@@ -435,6 +499,7 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
this.method = null;
|
this.method = null;
|
||||||
this.protocol = null;
|
this.protocol = null;
|
||||||
this.requestURI = null;
|
this.requestURI = null;
|
||||||
|
this.queryBytes = null;
|
||||||
this.contentType = null;
|
this.contentType = null;
|
||||||
this.host = null;
|
this.host = null;
|
||||||
this.connection = null;
|
this.connection = null;
|
||||||
@@ -443,6 +508,7 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
this.bodyparsed = false;
|
this.bodyparsed = false;
|
||||||
this.moduleid = 0;
|
this.moduleid = 0;
|
||||||
this.actionid = 0;
|
this.actionid = 0;
|
||||||
|
this.annotations = null;
|
||||||
this.currentUser = null;
|
this.currentUser = null;
|
||||||
|
|
||||||
this.attachment = null;
|
this.attachment = null;
|
||||||
@@ -613,6 +679,15 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
return requestURI;
|
return requestURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求参数的byte[]
|
||||||
|
*
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public byte[] getQueryBytes() {
|
||||||
|
return queryBytes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 截取getRequestURI最后的一个/后面的部分
|
* 截取getRequestURI最后的一个/后面的部分
|
||||||
*
|
*
|
||||||
@@ -1227,16 +1302,11 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
public String getParametersToString(String prefix) {
|
public String getParametersToString(String prefix) {
|
||||||
final StringBuilder sb = new StringBuilder();
|
byte[] rbs = queryBytes;
|
||||||
getParameters().forEach((k, v) -> {
|
if (rbs == null || rbs.length < 1) return "";
|
||||||
if (sb.length() > 0) sb.append('&');
|
Charset charset = this.context.getCharset();
|
||||||
try {
|
String str = charset == null ? new String(rbs, StandardCharsets.UTF_8) : new String(rbs, charset);
|
||||||
sb.append(k).append('=').append(URLEncoder.encode(v, "UTF-8"));
|
return (prefix == null) ? str : (prefix + str);
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return (sb.length() > 0 && prefix != null) ? (prefix + sb) : sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class HttpResourceServlet extends HttpServlet {
|
|||||||
|
|
||||||
public WatchThread(File root) throws IOException {
|
public WatchThread(File root) throws IOException {
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.setName("HttpResourceServlet-Watch-Thread");
|
this.setName("Redkale-HttpResourceServlet-Watch-Thread");
|
||||||
this.setDaemon(true);
|
this.setDaemon(true);
|
||||||
this.watcher = this.root.toPath().getFileSystem().newWatchService();
|
this.watcher = this.root.toPath().getFileSystem().newWatchService();
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ public class HttpResourceServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serRoot(String rootstr) {
|
public void setRoot(String rootstr) {
|
||||||
if (rootstr == null) return;
|
if (rootstr == null) return;
|
||||||
try {
|
try {
|
||||||
this.root = new File(rootstr).getCanonicalFile();
|
this.root = new File(rootstr).getCanonicalFile();
|
||||||
@@ -170,7 +170,7 @@ public class HttpResourceServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serRoot(File file) {
|
public void setRoot(File file) {
|
||||||
if (file == null) return;
|
if (file == null) return;
|
||||||
try {
|
try {
|
||||||
this.root = file.getCanonicalFile();
|
this.root = file.getCanonicalFile();
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
|
|
||||||
protected static final byte[] connectAliveBytes = "Connection: keep-alive\r\n".getBytes();
|
protected static final byte[] connectAliveBytes = "Connection: keep-alive\r\n".getBytes();
|
||||||
|
|
||||||
|
private static final byte[] fillContentLengthBytes = ("Content-Length: \r\n").getBytes();
|
||||||
|
|
||||||
|
private static final ZoneId ZONE_GMT = ZoneId.of("GMT");
|
||||||
|
|
||||||
private static final Set<OpenOption> options = new HashSet<>();
|
private static final Set<OpenOption> options = new HashSet<>();
|
||||||
|
|
||||||
private static final Map<Integer, String> httpCodes = new HashMap<>();
|
private static final Map<Integer, String> httpCodes = new HashMap<>();
|
||||||
@@ -103,8 +107,6 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
httpCodes.put(505, "HTTP Version Not Supported");
|
httpCodes.put(505, "HTTP Version Not Supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final ZoneId ZONE_GMT = ZoneId.of("GMT");
|
|
||||||
|
|
||||||
private int status = 200;
|
private int status = 200;
|
||||||
|
|
||||||
private String contentType = "";
|
private String contentType = "";
|
||||||
@@ -113,9 +115,15 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
|
|
||||||
private HttpCookie[] cookies;
|
private HttpCookie[] cookies;
|
||||||
|
|
||||||
private boolean headsended = false;
|
private int headWritedSize = -1; //0表示跳过header,正数表示header的字节长度。
|
||||||
|
|
||||||
|
private ByteBuffer headBuffer;
|
||||||
|
|
||||||
|
private int headLenPos = -1;
|
||||||
|
|
||||||
private BiFunction<HttpResponse, ByteBuffer[], ByteBuffer[]> bufferHandler;
|
private BiFunction<HttpResponse, ByteBuffer[], ByteBuffer[]> bufferHandler;
|
||||||
|
|
||||||
|
private Supplier<ByteBuffer> bodyBufferSupplier;
|
||||||
//------------------------------------------------
|
//------------------------------------------------
|
||||||
|
|
||||||
private final String plainContentType;
|
private final String plainContentType;
|
||||||
@@ -148,8 +156,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
return new ObjectPool<>(creatCounter, cycleCounter, max, creator, (x) -> ((HttpResponse) x).prepare(), (x) -> ((HttpResponse) x).recycle());
|
return new ObjectPool<>(creatCounter, cycleCounter, max, creator, (x) -> ((HttpResponse) x).prepare(), (x) -> ((HttpResponse) x).recycle());
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpResponse(HttpContext context, HttpRequest request, HttpResponseConfig config) {
|
public HttpResponse(HttpContext context, HttpRequest request, ObjectPool<Response> responsePool, HttpResponseConfig config) {
|
||||||
super(context, request);
|
super(context, request, responsePool);
|
||||||
this.plainContentType = config.plainContentType == null || config.plainContentType.isEmpty() ? "text/plain; charset=utf-8" : config.plainContentType;
|
this.plainContentType = config.plainContentType == null || config.plainContentType.isEmpty() ? "text/plain; charset=utf-8" : config.plainContentType;
|
||||||
this.jsonContentType = config.jsonContentType == null || config.jsonContentType.isEmpty() ? "application/json; charset=utf-8" : config.jsonContentType;
|
this.jsonContentType = config.jsonContentType == null || config.jsonContentType.isEmpty() ? "application/json; charset=utf-8" : config.jsonContentType;
|
||||||
this.plainContentTypeBytes = ("Content-Type: " + this.plainContentType + "\r\n").getBytes();
|
this.plainContentTypeBytes = ("Content-Type: " + this.plainContentType + "\r\n").getBytes();
|
||||||
@@ -163,6 +171,11 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
this.hasRender = renders != null && !renders.isEmpty();
|
this.hasRender = renders != null && !renders.isEmpty();
|
||||||
this.onlyoneHttpRender = renders != null && renders.size() == 1 ? renders.get(0) : null;
|
this.onlyoneHttpRender = renders != null && renders.size() == 1 ? renders.get(0) : null;
|
||||||
this.contentType = this.plainContentType;
|
this.contentType = this.plainContentType;
|
||||||
|
this.bodyBufferSupplier = () -> {
|
||||||
|
if (headWritedSize >= 0 || bufferHandler != null) return channel.pollWriteBuffer(); //bufferHandler 需要cached的请求不能带上header
|
||||||
|
if (contentLength < 0) contentLength = -2;
|
||||||
|
return createHeader();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -174,18 +187,29 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void prepare() {
|
||||||
|
super.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
this.status = 200;
|
this.status = 200;
|
||||||
this.contentLength = -1;
|
this.contentLength = -1;
|
||||||
this.contentType = null;
|
this.contentType = null;
|
||||||
this.cookies = null;
|
this.cookies = null;
|
||||||
this.headsended = false;
|
this.headWritedSize = -1;
|
||||||
|
this.headBuffer = null;
|
||||||
|
this.headLenPos = -1;
|
||||||
this.header.clear();
|
this.header.clear();
|
||||||
this.bufferHandler = null;
|
this.bufferHandler = null;
|
||||||
return super.recycle();
|
return super.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Supplier<ByteBuffer> getBodyBufferSupplier() {
|
||||||
|
return bodyBufferSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init(AsyncConnection channel) {
|
protected void init(AsyncConnection channel) {
|
||||||
super.init(channel);
|
super.init(channel);
|
||||||
@@ -259,7 +283,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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -280,15 +304,6 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
return context.loadAsyncHandlerCreator(handlerClass).create(createAsyncHandler());
|
return context.loadAsyncHandlerCreator(handlerClass).create(createAsyncHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取ByteBuffer生成器
|
|
||||||
*
|
|
||||||
* @return ByteBuffer生成器
|
|
||||||
*/
|
|
||||||
public Supplier<ByteBuffer> getBufferSupplier() {
|
|
||||||
return getBodyBufferSupplier();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将对象以JSON格式输出
|
* 将对象以JSON格式输出
|
||||||
*
|
*
|
||||||
@@ -385,7 +400,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
|
this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
|
||||||
this.header.addValue("retinfo", ret.getRetinfo());
|
this.header.addValue("retinfo", ret.getRetinfo());
|
||||||
}
|
}
|
||||||
finish(request.getJsonConvert().convertTo(getBodyBufferSupplier(), ret));
|
Convert convert = ret == null ? null : ret.convert();
|
||||||
|
if (convert == null || !(convert instanceof TextConvert)) convert = request.getJsonConvert();
|
||||||
|
finish(convert.convertTo(getBodyBufferSupplier(), ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -471,7 +488,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,9 +506,11 @@ 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 org.redkale.service.RetResult) {
|
||||||
|
finishJson((org.redkale.service.RetResult) obj);
|
||||||
} else if (obj instanceof HttpResult) {
|
} else if (obj instanceof HttpResult) {
|
||||||
HttpResult result = (HttpResult) obj;
|
HttpResult result = (HttpResult) obj;
|
||||||
if (result.getContentType() != null) setContentType(result.getContentType());
|
if (result.getContentType() != null) setContentType(result.getContentType());
|
||||||
@@ -501,7 +520,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
} else if (result.getResult() instanceof CharSequence) {
|
} else if (result.getResult() instanceof CharSequence) {
|
||||||
finish(result.getResult().toString());
|
finish(result.getResult().toString());
|
||||||
} else {
|
} else {
|
||||||
finish(convert, result.getResult());
|
Convert cc = result.convert();
|
||||||
|
if (cc == null || !(cc instanceof TextConvert)) cc = convert;
|
||||||
|
finish(cc, result.getResult());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hasRender) {
|
if (hasRender) {
|
||||||
@@ -614,15 +635,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,17 +646,32 @@ 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; //避免重复关闭
|
||||||
|
final byte[] content = bs == null ? new byte[0] : bs;
|
||||||
|
if (this.headWritedSize < 0) {
|
||||||
this.contentType = contentType;
|
this.contentType = contentType;
|
||||||
if (this.context.getBufferCapacity() >= bs.length) {
|
this.contentLength = content.length;
|
||||||
|
ByteBuffer headbuf = createHeader();
|
||||||
|
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 {
|
||||||
|
if (this.context.getBufferCapacity() >= content.length) {
|
||||||
ByteBuffer buffer = getBodyBufferSupplier().get();
|
ByteBuffer buffer = getBodyBufferSupplier().get();
|
||||||
buffer.put(bs);
|
buffer.put(content);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
this.finish(false, buffer);
|
this.finish(false, buffer);
|
||||||
} else {
|
} else {
|
||||||
this.finish(false, ByteBuffer.wrap(bs));
|
this.finish(false, ByteBuffer.wrap(content));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将指定ByteBuffer按响应结果输出
|
* 将指定ByteBuffer按响应结果输出
|
||||||
*
|
*
|
||||||
@@ -663,7 +691,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
@Override
|
@Override
|
||||||
public void finish(boolean kill, ByteBuffer buffer) {
|
public void finish(boolean kill, ByteBuffer buffer) {
|
||||||
if (isClosed()) return; //避免重复关闭
|
if (isClosed()) return; //避免重复关闭
|
||||||
if (!this.headsended) {
|
if (this.headWritedSize < 0) {
|
||||||
this.contentLength = buffer == null ? 0 : buffer.remaining();
|
this.contentLength = buffer == null ? 0 : buffer.remaining();
|
||||||
ByteBuffer headbuf = createHeader();
|
ByteBuffer headbuf = createHeader();
|
||||||
headbuf.flip();
|
headbuf.flip();
|
||||||
@@ -701,7 +729,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
if (bufs != null) buffers = bufs;
|
if (bufs != null) buffers = bufs;
|
||||||
}
|
}
|
||||||
if (kill) refuseAlive();
|
if (kill) refuseAlive();
|
||||||
if (!this.headsended) {
|
if (this.headWritedSize < 0) {
|
||||||
long len = 0;
|
long len = 0;
|
||||||
for (ByteBuffer buf : buffers) {
|
for (ByteBuffer buf : buffers) {
|
||||||
len += buf.remaining();
|
len += buf.remaining();
|
||||||
@@ -718,6 +746,17 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
super.finish(kill, newbuffers);
|
super.finish(kill, newbuffers);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (this.headLenPos > 0 && buffers[0] == headBuffer) {
|
||||||
|
long contentlen = -this.headWritedSize;
|
||||||
|
for (ByteBuffer buf : buffers) {
|
||||||
|
contentlen += buf.remaining();
|
||||||
|
}
|
||||||
|
byte[] lenBytes = String.valueOf(contentlen).getBytes();
|
||||||
|
int start = this.headLenPos - lenBytes.length;
|
||||||
|
for (int i = 0; i < lenBytes.length; i++) {
|
||||||
|
headBuffer.put(start + i, lenBytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
super.finish(kill, buffers);
|
super.finish(kill, buffers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -731,7 +770,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
* @param handler 异步回调函数
|
* @param handler 异步回调函数
|
||||||
*/
|
*/
|
||||||
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler) {
|
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler) {
|
||||||
if (!this.headsended) {
|
if (this.headWritedSize < 0) {
|
||||||
if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining();
|
if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining();
|
||||||
ByteBuffer headbuf = createHeader();
|
ByteBuffer headbuf = createHeader();
|
||||||
headbuf.flip();
|
headbuf.flip();
|
||||||
@@ -754,7 +793,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
* @param handler 异步回调函数
|
* @param handler 异步回调函数
|
||||||
*/
|
*/
|
||||||
public <A> void sendBody(ByteBuffer[] buffers, A attachment, CompletionHandler<Integer, A> handler) {
|
public <A> void sendBody(ByteBuffer[] buffers, A attachment, CompletionHandler<Integer, A> handler) {
|
||||||
if (!this.headsended) {
|
if (this.headWritedSize < 0) {
|
||||||
if (this.contentLength < 0) {
|
if (this.contentLength < 0) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
if (buffers != null && buffers.length > 0) {
|
if (buffers != null && buffers.length > 0) {
|
||||||
@@ -837,8 +876,10 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
}
|
}
|
||||||
this.contentLength = length;
|
this.contentLength = length;
|
||||||
if (filename != null && !filename.isEmpty() && file != null) {
|
if (filename != null && !filename.isEmpty() && file != null) {
|
||||||
|
if (this.header.getValue("Content-Disposition") == null) {
|
||||||
addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
|
addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.contentType = MimeType.getByFilename(filename == null || filename.isEmpty() ? file.getName() : filename);
|
this.contentType = MimeType.getByFilename(filename == null || filename.isEmpty() ? file.getName() : filename);
|
||||||
if (this.contentType == null) this.contentType = "application/octet-stream";
|
if (this.contentType == null) this.contentType = "application/octet-stream";
|
||||||
String range = request.getHeader("Range");
|
String range = request.getHeader("Range");
|
||||||
@@ -879,14 +920,20 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
|
|
||||||
//Header大小不能超过一个ByteBuffer的容量
|
//Header大小不能超过一个ByteBuffer的容量
|
||||||
protected ByteBuffer createHeader() {
|
protected ByteBuffer createHeader() {
|
||||||
this.headsended = true;
|
ByteBuffer buffer = this.channel.pollWriteBuffer();
|
||||||
ByteBuffer buffer = this.pollWriteReadBuffer();
|
int oldpos = buffer.position();
|
||||||
if (this.status == 200) {
|
if (this.status == 200) {
|
||||||
buffer.put(status200Bytes);
|
buffer.put(status200Bytes);
|
||||||
} else {
|
} else {
|
||||||
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());
|
||||||
|
} else if (this.contentLength == -2) {
|
||||||
|
buffer.put(fillContentLengthBytes);
|
||||||
|
this.headLenPos = buffer.position() - 2; //去掉\r\n
|
||||||
|
}
|
||||||
|
if (!this.request.isWebSocket()) {
|
||||||
if (this.contentType == this.jsonContentType) {
|
if (this.contentType == this.jsonContentType) {
|
||||||
buffer.put(this.jsonContentTypeBytes);
|
buffer.put(this.jsonContentTypeBytes);
|
||||||
} else if (this.contentType == null || this.contentType == this.plainContentType) {
|
} else if (this.contentType == null || this.contentType == this.plainContentType) {
|
||||||
@@ -894,9 +941,13 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
} else {
|
} else {
|
||||||
buffer.put(("Content-Type: " + (this.contentType == null ? this.plainContentType : this.contentType) + "\r\n").getBytes());
|
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());
|
||||||
|
|
||||||
|
if (this.header.getValue("Connection") == null) {
|
||||||
buffer.put(this.request.isKeepAlive() ? connectAliveBytes : connectCloseBytes);
|
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) {
|
||||||
@@ -929,7 +980,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
}
|
}
|
||||||
if (request.newsessionid != null) {
|
if (request.newsessionid != null) {
|
||||||
String domain = defaultCookie == null ? null : defaultCookie.getDomain();
|
String domain = defaultCookie == null ? null : defaultCookie.getDomain();
|
||||||
if (domain == null) {
|
if (domain == null || domain.isEmpty()) {
|
||||||
domain = "";
|
domain = "";
|
||||||
} else {
|
} else {
|
||||||
domain = "Domain=" + domain + "; ";
|
domain = "Domain=" + domain + "; ";
|
||||||
@@ -937,9 +988,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
String path = defaultCookie == null ? null : defaultCookie.getPath();
|
String path = defaultCookie == null ? null : defaultCookie.getPath();
|
||||||
if (path == null || path.isEmpty()) path = "/";
|
if (path == null || path.isEmpty()) path = "/";
|
||||||
if (request.newsessionid.isEmpty()) {
|
if (request.newsessionid.isEmpty()) {
|
||||||
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=" + path + "; Max-Age=0; HttpOnly\r\n").getBytes());
|
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=/; Max-Age=0; HttpOnly\r\n").getBytes());
|
||||||
} else {
|
} else {
|
||||||
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=" + path + "; HttpOnly\r\n").getBytes());
|
buffer.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=/; HttpOnly\r\n").getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.cookies != null) {
|
if (this.cookies != null) {
|
||||||
@@ -953,6 +1004,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffer.put(LINE);
|
buffer.put(LINE);
|
||||||
|
this.headWritedSize = buffer.position() - oldpos;
|
||||||
|
this.headBuffer = buffer;
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -978,7 +1031,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
* @return HttpResponse
|
* @return HttpResponse
|
||||||
*/
|
*/
|
||||||
public HttpResponse skipHeader() {
|
public HttpResponse skipHeader() {
|
||||||
this.headsended = true;
|
this.headWritedSize = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1185,7 +1238,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
context.offerBuffer(attachment);
|
channel.offerBuffer(attachment);
|
||||||
finish(true);
|
finish(true);
|
||||||
try {
|
try {
|
||||||
filechannel.close();
|
filechannel.close();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user