242 Commits
1.3.0 ... 1.7.0

Author SHA1 Message Date
Redkale
f9f2e080da 2017-04-30 19:25:33 +08:00
Redkale
027fa3a18b 2017-04-30 19:25:13 +08:00
Redkale
d9f50d63f0 2017-04-30 18:48:10 +08:00
Redkale
181486c348 2017-04-30 18:30:53 +08:00
Redkale
74adfdfc99 2017-04-30 17:33:15 +08:00
Redkale
c3783eb041 2017-04-30 17:08:59 +08:00
Redkale
77451561e6 2017-04-23 21:22:38 +08:00
Redkale
59d30b05f2 2017-04-23 21:08:18 +08:00
Redkale
2fcf0bb644 2017-04-23 21:03:08 +08:00
Redkale
71ab9c9728 去掉ServiceWrapper 2017-04-23 20:19:07 +08:00
Redkale
09165127e3 2017-04-23 16:47:24 +08:00
Redkale
c28310e0df 2017-04-23 16:03:24 +08:00
Redkale
51435a1c33 2017-04-23 14:19:34 +08:00
Redkale
83c70b9767 2017-04-20 22:03:07 +08:00
Redkale
5534dcd476 2017-04-20 15:03:32 +08:00
Redkale
d18a55deaf 2017-04-20 14:32:15 +08:00
Redkale
ae2d64991c 2017-04-20 14:28:59 +08:00
Redkale
ecb6b80e5e 2017-04-20 14:10:48 +08:00
Redkale
cf332fa67a 2017-04-20 14:08:13 +08:00
Redkale
ffa80c9212 2017-04-20 12:21:47 +08:00
Redkale
7463a8f6b5 2017-04-19 22:58:03 +08:00
Redkale
a168897784 2017-04-19 22:42:04 +08:00
Redkale
d39b3856ca 2017-04-19 18:52:20 +08:00
Redkale
ca9f74185b 2017-04-19 09:50:17 +08:00
Redkale
c35e421ba3 2017-04-19 07:55:45 +08:00
Redkale
65755e0787 2017-04-19 07:54:05 +08:00
Redkale
366c3becc4 2017-04-19 07:44:59 +08:00
Redkale
a1ac6ec543 2017-04-18 17:10:41 +08:00
Redkale
b27bbb7836 2017-03-31 08:11:46 +08:00
Redkale
a57574dd10 2017-03-30 23:19:54 +08:00
Redkale
a7dd22569c 2017-03-30 16:53:20 +08:00
Redkale
0bc0755fb3 2017-03-29 13:55:16 +08:00
Redkale
c2edb60218 2017-03-28 10:42:11 +08:00
Redkale
60c1a82a62 2017-03-27 10:03:55 +08:00
Redkale
e3205128b4 2017-03-27 08:23:22 +08:00
Redkale
a9dff0360f 2017-03-26 15:42:56 +08:00
Redkale
1e871cbee5 2017-03-26 15:02:54 +08:00
Redkale
41aadf33f3 2017-03-26 14:28:06 +08:00
Redkale
679567c85a 2017-03-26 14:15:36 +08:00
Redkale
b77050250c 2017-03-25 22:03:19 +08:00
Redkale
e178d1120b 2017-03-25 14:36:10 +08:00
Redkale
eca138b671 2017-03-24 11:28:01 +08:00
Redkale
0366aef672 2017-03-24 11:11:11 +08:00
Redkale
30103e5c8f 2017-03-23 14:20:35 +08:00
Redkale
cbba7701d8 2017-03-23 14:17:06 +08:00
Redkale
da53bd7db9 2017-03-23 11:20:43 +08:00
Redkale
9e7999da0f 2017-03-22 16:42:54 +08:00
Redkale
2c96f991d5 2017-03-22 16:36:09 +08:00
Redkale
67f8127452 2017-03-22 16:34:51 +08:00
Redkale
bce498885e 异步接口支持AsyncHandler子类 2017-03-22 16:05:10 +08:00
Redkale
eb57a25698 PrepareServlet.addServlet方法改为线程安全 2017-03-22 11:56:21 +08:00
Redkale
4e83e5bf71 2017-03-22 11:28:21 +08:00
Redkale
19a44ce8cf 2017-03-22 10:31:14 +08:00
Redkale
0bd0df3245 2017-03-21 17:16:28 +08:00
Redkale
4f0163736f 2017-03-21 13:09:11 +08:00
Redkale
8d03f52f09 2017-03-21 13:06:15 +08:00
Redkale
815267a590 2017-03-21 12:53:00 +08:00
Redkale
77f8d442b2 2017-03-21 12:45:41 +08:00
Redkale
aacda5d35e 2017-03-21 12:35:12 +08:00
Redkale
58d02f6471 2017-03-21 12:32:42 +08:00
Redkale
c735874cff 2017-03-21 12:02:54 +08:00
Redkale
045029b4a9 2017-03-21 11:55:57 +08:00
Redkale
f6b5882cd4 2017-03-21 11:45:40 +08:00
Redkale
63a9005e6b 2017-03-21 09:47:18 +08:00
Redkale
c4923f317b 2017-03-21 09:34:35 +08:00
Redkale
15e03c0459 2017-03-21 09:14:32 +08:00
Redkale
74f4ddf50b 2017-03-20 22:37:13 +08:00
Redkale
fdc868641d 2017-03-20 21:05:28 +08:00
Redkale
910eb88c55 2017-03-20 17:54:58 +08:00
Redkale
b597131de4 2017-03-20 17:33:32 +08:00
Redkale
56d5f97556 2017-03-20 17:08:54 +08:00
Redkale
b364dd5811 Service异步接口的返回类型强制约束为void,且必须存在对应的同步方法 2017-03-20 16:15:07 +08:00
Redkale
4fec27498c 2017-03-20 13:53:13 +08:00
Redkale
7a195ecf23 2017-03-20 13:37:40 +08:00
Redkale
95b7e819cd 2017-03-20 13:25:42 +08:00
Redkale
73d243aaf1 2017-03-20 10:59:08 +08:00
Redkale
998fecdd51 2017-03-19 21:36:16 +08:00
Redkale
b1ddc0e3a5 2017-03-18 19:21:05 +08:00
Redkale
641ff4709d 2017-03-18 19:16:06 +08:00
Redkale
13f2fbf7d6 2017-03-17 20:18:18 +08:00
Redkale
62f9882314 2017-03-17 20:08:24 +08:00
Redkale
7f270eb9d7 2017-03-17 20:04:09 +08:00
Redkale
974a6bfeaa 2017-03-17 18:18:58 +08:00
Redkale
4958b454af 2017-03-17 18:04:17 +08:00
Redkale
3531d0963d 2017-03-17 17:57:24 +08:00
Redkale
41e6497a2e 2017-03-17 16:49:55 +08:00
Redkale
3439fab690 2017-03-17 16:07:41 +08:00
Redkale
14274c8d04 2017-03-17 15:57:49 +08:00
Redkale
b3cbd9be71 2017-03-17 15:21:35 +08:00
Redkale
b1d810188c 2017-03-17 14:54:00 +08:00
Redkale
4b48f85162 2017-03-17 13:20:26 +08:00
Redkale
738b02e1b9 优化DataSource的异步接口 2017-03-17 13:09:28 +08:00
Redkale
dc487f9226 2017-03-17 12:03:42 +08:00
Redkale
bb2f43c317 2017-03-17 09:26:44 +08:00
Redkale
be61aef123 Service、DataSource、CacheSource增加异步接口 2017-03-16 20:04:20 +08:00
Redkale
6ad7888e85 2017-03-16 20:02:34 +08:00
Redkale
242adb3c9e 2017-03-16 17:46:38 +08:00
Redkale
8654c69d0c 2017-03-16 17:38:18 +08:00
Redkale
a7999ff160 2017-03-14 17:03:29 +08:00
Redkale
9c04b8aab0 2017-03-10 18:59:36 +08:00
Redkale
3643fefc9c 2017-03-09 17:22:02 +08:00
Redkale
47189901e5 2017-03-09 15:44:43 +08:00
Redkale
2577684897 2017-03-09 15:08:36 +08:00
Redkale
77396df8fd 2017-03-09 14:04:36 +08:00
Redkale
c517a1d469 增加javadoc注释 2017-03-09 11:44:12 +08:00
Redkale
b7d7e6567b 2017-03-09 11:19:13 +08:00
Redkale
67807e913e 2017-03-09 09:49:14 +08:00
Redkale
19a950dab5 2017-03-08 20:04:09 +08:00
Redkale
79b91f8386 @WebAction替换成@WebMapping 2017-03-08 18:56:07 +08:00
Redkale
0359a4b7e9 2017-03-08 17:28:33 +08:00
Redkale
d89f410749 2017-03-08 17:22:56 +08:00
Redkale
850f6dd060 2017-03-08 17:05:21 +08:00
Redkale
d891c6c8dc 2017-03-08 14:25:03 +08:00
Redkale
0a4a88ed5a 2017-03-08 14:03:05 +08:00
Redkale
3c02219da0 2017-03-08 09:57:08 +08:00
Redkale
65efc3372e 2017-03-07 17:44:50 +08:00
Redkale
3acea66788 2017-03-07 15:47:39 +08:00
Redkale
b448514e40 2017-03-07 11:58:27 +08:00
Redkale
024147344b 2017-03-07 10:09:26 +08:00
Redkale
52a34d3871 2017-03-07 09:42:03 +08:00
Redkale
1ada26e4dd 2017-03-07 09:39:16 +08:00
Redkale
94d1b61f81 2017-03-06 15:18:50 +08:00
Redkale
29299edb90 2017-03-06 14:45:35 +08:00
Redkale
a2e2c5e178 2017-03-06 12:02:00 +08:00
Redkale
8ae39df2e8 2017-03-06 09:29:25 +08:00
Redkale
508b269a82 2017-03-03 18:40:45 +08:00
Redkale
a8627b6105 2017-03-03 18:21:09 +08:00
Redkale
8fee6b2c68 2017-03-03 18:05:11 +08:00
Redkale
dd58571ffd 2017-03-03 17:50:50 +08:00
Redkale
8c25683cc5 增加javadoc注释 2017-03-03 14:49:32 +08:00
Redkale
a96f003b8c 2017-03-03 11:45:55 +08:00
Redkale
ff01443246 2017-03-02 19:59:42 +08:00
Redkale
e915a253f8 2017-03-02 16:03:29 +08:00
Redkale
b463389733 2017-03-02 15:43:34 +08:00
Redkale
41c97b92c7 删除DataSource.updateColumns方法,使用 DataSource.updateColumn代替 2017-03-02 14:21:47 +08:00
Redkale
1142f81e9c 删掉HttpResponse.finishJsResult方法 2017-03-02 14:13:29 +08:00
Redkale
5bc9f77b7b 修复HttpRequest.getBody由于URLDecode导致的BUG 2017-03-02 12:35:14 +08:00
Redkale
c5d0582807 修复HttpRequest.getBody由于URLDecode导致内容多余的BUG 2017-03-02 11:52:22 +08:00
Redkale
525e65d152 增加javadoc注释 2017-03-02 10:41:15 +08:00
Redkale
d948c7af47 增加javadoc注释 2017-03-02 10:02:45 +08:00
Redkale
11a29b4ed6 2017-03-01 20:59:00 +08:00
Redkale
e31c4a3041 DataSource增加支持Blob(byte[])类型字段功能 2017-02-28 13:37:38 +08:00
Redkale
2928d5fc93 2017-02-28 10:01:13 +08:00
Redkale
12fc6f7f10 2017-02-27 17:30:03 +08:00
Redkale
4bd8c207b4 增加javadoc注释 2017-02-27 17:15:14 +08:00
Redkale
be030a3640 增加javadoc注释 2017-02-27 17:11:23 +08:00
Redkale
ebaa250f7b 增加javadoc注释 2017-02-27 17:07:00 +08:00
Redkale
826a2d7ee6 增加javadoc注释 2017-02-27 15:06:31 +08:00
Redkale
e476cf8176 2017-02-27 13:54:23 +08:00
Redkale
03115694f9 增加javadoc注释 2017-02-27 12:01:39 +08:00
Redkale
26ffb04834 增加javadoc注释 2017-02-27 11:56:18 +08:00
Redkale
2979fcc33d 增加javadoc注释 2017-02-27 11:19:40 +08:00
Redkale
9a29a11e22 2017-02-25 12:53:54 +08:00
Redkale
d73a27be71 2017-02-25 12:44:24 +08:00
Redkale
d77f424504 2017-02-25 12:27:19 +08:00
Redkale
3142ad6041 2017-02-24 15:46:00 +08:00
Redkale
6044f014c7 2017-02-24 09:04:16 +08:00
Redkale
d1cfdfa14f 2017-02-23 20:33:03 +08:00
Redkale
8f9bfc3f28 兼容javax.persistence.jdbc.driver为空的情况 2017-02-23 20:16:58 +08:00
Redkale
9ae847d392 FilterFuncColumn支持多字段名 2017-02-23 19:26:13 +08:00
Redkale
178226b730 DataSource增加getNumberMap方法,用于查询多个字段的统计值 2017-02-23 19:06:40 +08:00
Redkale
801e45abce 2017-02-23 17:45:01 +08:00
Redkale
cd54a7040a 2017-02-23 15:40:17 +08:00
Redkale
3bd880b061 2017-02-23 15:29:04 +08:00
Redkale
bf355cce28 2017-02-23 15:15:43 +08:00
Redkale
58d08c5787 @Cacheable增加定时更新缓存功能 2017-02-22 20:57:13 +08:00
Redkale
a778af73d8 修复HttpRequest.getRemoteAddress()方法中channel已关闭会抛空指针异常的BUG 2017-02-22 16:06:40 +08:00
Redkale
7ca95c3549 2017-02-22 09:10:40 +08:00
Redkale
54933ac3ac Utility增加 删除掉字符串数组中包含指定的字符串 方法 2017-02-21 20:27:19 +08:00
Redkale
255048bf5b Response增加output字段,便于RecycleListener获取输出结果 2017-02-21 16:35:08 +08:00
Redkale
206fa19f3e 2017-02-17 14:12:33 +08:00
Redkale
f0e9047f8c 2017-02-17 14:02:24 +08:00
Redkale
698966d551 删掉 DistributeGenerator 功能 2017-02-16 11:29:49 +08:00
Redkale
fc6b5cb458 2017-02-15 20:56:28 +08:00
Redkale
9eee3bfa58 增加 java.util.logging.FileHandler.unusual 特性 2017-02-15 20:46:30 +08:00
Redkale
0adc0845fd 2017-02-15 20:07:30 +08:00
Redkale
92f98eff5f 2017-02-15 09:57:10 +08:00
Redkale
d97f8acf23 2017-02-10 20:08:47 +08:00
Redkale
47e14bf2ec 2017-02-10 17:38:51 +08:00
Redkale
8eed4083bc 2017-02-10 16:55:39 +08:00
Redkale
9ef7641cd1 2017-02-09 16:44:31 +08:00
Redkale
bafb6065c8 2017-02-09 14:53:16 +08:00
Redkale
8b2460b8ab 2017-02-09 13:38:24 +08:00
Redkale
827172e743 2017-02-09 11:52:04 +08:00
Redkale
fa9bd30de5 2017-02-04 15:01:39 +08:00
Redkale
78e66ff74b 2017-02-04 14:59:10 +08:00
Redkale
7e8d1c3567 2017-02-04 09:04:35 +08:00
Redkale
c3a7603674 2017-02-03 17:25:56 +08:00
Redkale
4b8cfbba00 2017-02-03 16:52:57 +08:00
Redkale
30771e5366 2017-02-03 16:43:12 +08:00
Redkale
313c7f4ba1 2017-02-03 16:37:08 +08:00
Redkale
ece4215a8a 2017-02-03 15:03:11 +08:00
Redkale
7ea740edf1 Update RestParam.java 2017-02-02 17:23:02 +08:00
Redkale
716f4e6934 Update RestParam.java 2017-02-02 17:21:43 +08:00
Redkale
90ab302667 2017-01-18 22:55:29 +08:00
Redkale
4695949362 2017-01-18 19:04:57 +08:00
Redkale
4827893a0d 2017-01-18 10:54:02 +08:00
Redkale
9276f220b0 2017-01-17 20:12:38 +08:00
Redkale
4071a5d165 2017-01-17 13:37:34 +08:00
Redkale
da0ff24af6 2017-01-17 13:28:23 +08:00
Redkale
afef635146 2017-01-17 13:23:11 +08:00
Redkale
eda9d1c780 2017-01-16 14:11:35 +08:00
Redkale
4b5749bc60 2017-01-16 11:50:19 +08:00
Redkale
6bb23008c2 2017-01-11 10:37:53 +08:00
Redkale
7746971b60 2017-01-11 10:35:56 +08:00
Redkale
bc20c82fef 2017-01-11 10:24:49 +08:00
Redkale
fff70ed241 2017-01-11 10:03:43 +08:00
Redkale
c590d45ce0 2017-01-10 20:01:09 +08:00
Redkale
8bab9ad22b 2017-01-10 18:10:02 +08:00
Redkale
3c457dad2a 2017-01-10 16:42:41 +08:00
Redkale
eaae598234 2017-01-09 15:05:14 +08:00
Redkale
606faf1bf8 2017-01-09 10:38:34 +08:00
Redkale
ae9aa94323 2017-01-09 10:27:13 +08:00
Redkale
2e41e44294 2016-12-29 11:15:21 +08:00
Redkale
d806d9d6ff 2016-12-29 10:34:43 +08:00
Redkale
1260736c14 2016-12-26 17:31:34 +08:00
Redkale
08c5cbbbf3 2016-12-26 15:16:20 +08:00
Redkale
af0726cd79 2016-12-25 15:47:46 +08:00
Redkale
ce2279030d 2016-12-25 15:45:41 +08:00
Redkale
83aba2ebee 2016-12-23 18:20:04 +08:00
Redkale
5c11742b51 2016-12-17 17:14:22 +08:00
Redkale
5295e04275 2016-12-15 14:38:33 +08:00
Redkale
47f723e63b 2016-12-15 09:54:23 +08:00
Redkale
54956e47d2 2016-12-15 09:11:28 +08:00
Redkale
b2cbdf6642 2016-12-14 20:43:41 +08:00
Redkale
989d1c6db9 解决updateColumn多表关联更新的BUG 2016-12-11 20:40:29 +08:00
Redkale
e139b0cc5d 2016-12-11 19:56:33 +08:00
Redkale
66261e98b5 2016-12-11 19:22:12 +08:00
Redkale
d9a268d30a 2016-12-11 19:10:51 +08:00
Redkale
a8bc50a947 2016-12-09 17:06:26 +08:00
Redkale
6aa96daae2 2016-12-09 14:17:16 +08:00
Redkale
293805a55e 2016-12-09 11:17:03 +08:00
Redkale
8b6319888c Update README.md 2016-12-02 11:10:54 +08:00
Redkale
408676e97a Update README.md 2016-12-02 11:09:15 +08:00
Redkale
1fabbae4f6 2016-11-28 10:43:38 +08:00
Redkale
09a5b41d96 2016-11-25 17:20:45 +08:00
Redkale
9d85a4dcaf 2016-11-25 17:06:03 +08:00
Redkale
9bc60c1c47 2016-11-25 15:53:37 +08:00
Redkale
92aff864ef 2016-11-25 11:40:49 +08:00
Redkale
254e2e8ccd 2016-11-25 11:28:11 +08:00
Redkale
2480d127ac 2016-11-25 10:16:58 +08:00
Redkale
cc3d82e864 2016-11-25 10:09:06 +08:00
173 changed files with 12897 additions and 4039 deletions

View File

@@ -8,14 +8,14 @@
<li>提供HTTP服务同时内置JSON功能与限时缓存功能</li> <li>提供HTTP服务同时内置JSON功能与限时缓存功能</li>
<li>TCP层完全使用NIO.2并统一TCP与UDP的接口换</li> <li>TCP层完全使用NIO.2并统一TCP与UDP的接口换</li>
<li>提供分布式与集中式部署的无缝切换</li> <li>提供分布式与集中式部署的无缝切换</li>
<li>提供类似JPA功能包含数据缓存自动同步与简洁的数据层操作接口</li> <li>提供类似JPA功能包含数据缓存自动同步、分表分库与简洁的数据层操作接口</li>
<li>可以动态修改已依赖注入的资源</li> <li>可以动态修改已依赖注入的资源</li>
</ol> </ol>
<strong>Redkale 设计理念</strong> <strong>Redkale 设计理念</strong>
<p> <p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架,不仅是使用了Java8的新语法,更多是设计上与主流框架有不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量而且也可以动态更改已注入的资源。Spring提倡控制反转思想偏偏自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者不想使用Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务开发者想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现。这其实包含了控制反转的思想让框架里的零件可以让开发者控制。<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架,Redkale在接口定义上使用了Java 8大量的新语法,接口有默认实现、接口带静态方法、重复注解等特性,同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量并且可动态更改已注入的资源。Spring提倡控制反转思想自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务若想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想,让框架里的各个组件均可让开发者控制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单也是Redkale的一个特点并非不足,从一个良好的设计习惯或架构上来看,有些常用功能是不需要提供的,如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集的数字计算不是Java的专长同时一个稍好的提供HTTP服务的架构不会将Java动态服务器放在最前端通常前面会放nginx或apache除了负载均衡还能静动分离既然Java服务器前面有C写的服务器那么HTTPS的加解密就应该交给前面的服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP(如果初级程序员还花大量时间去学习基于JSP的Struts或Spring MVC框架就有点跟不上时代了)。Redkale在功能上做了筛选不会只因为迎合主流而提供,而是以良好的设计思想为指导。这是Redkale很重要的一个思想 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单体现了Redkale的简易性,而并非不足从一个良好的设计习惯或架构上来看有些常用功能是不需要提供的如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集的计算不是Java的专长通常提供HTTP服务的架构不会将Java动态服务器放在最前端而是在前方会放nginx或apache除了负载均衡还能静动分离因此HTTPS的加解密应交给nginx这样的高性能服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能方便兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选不会为迎合主流而提供而是以良好的设计思想为指导。这是Redkale的主导思维
</p> </p>

32
assembly.xml Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>redkale</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/bin</directory>
<outputDirectory>bin</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/conf</directory>
<outputDirectory>conf</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/logs</directory>
<outputDirectory>logs</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<useTransitiveDependencies>false</useTransitiveDependencies>
<outputDirectory>lib</outputDirectory>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>

View File

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

150
pom.xml Normal file
View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.redkale</groupId>
<artifactId>redkale</artifactId>
<packaging>jar</packaging>
<url>http://redkale.org</url>
<description>redkale -- java framework</description>
<version>1.6.2</version>
<licenses>
<license>
<name>Apache 2</name>
<url>http://www.apache.org/licenses/</url>
<distribution>repo</distribution>
<comments>Apache License</comments>
</license>
</licenses>
<developers>
<developer>
<id>Redkale</id>
<name>redkale</name>
<email>redkale@qq.com</email>
<url>http://redkale.org</url>
<roles>
<role>Project Manager</role>
<role>Architect</role>
</roles>
<organization>redkale</organization>
<organizationUrl>http://redkale.org</organizationUrl>
<properties>
<dept>No</dept>
</properties>
<timezone>8</timezone>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<name>Redkale</name>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<scm>
<url>https://github.com/redkale/redkale</url>
<connection>scm:git:git@github.com/redkale/redkale.git</connection>
<developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<mainClass>org.redkale.boot.Application</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>redkale</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -42,8 +42,8 @@
一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内 一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
一个group节点对应一个 Transport 对象。 一个group节点对应一个 Transport 对象。
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。 name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol只能是UDP TCP 默认TCP protocol范围:UDP TCP 默认TCP
kind: 与SNCP服务连接时的数据传输类型可选值有:rest(不区分大小写);值为空或空字符串表示按SNCP协议传输; 为rest表示按REST传输。默认值为空 subprotocol: 子协议,预留字段。默认值为空
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。 注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
--> -->
<group name="" protocol="TCP"> <group name="" protocol="TCP">
@@ -59,7 +59,7 @@
</group> </group>
<!-- <!--
【节点全局唯一】 【节点全局唯一】
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入, 被注解的字段类型只能是String、primitive class 全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。 如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。 如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
load: 加载文件,多个用;隔开。 load: 加载文件,多个用;隔开。
@@ -70,6 +70,8 @@
System.setProperty("convert.bson.pool.size", "128"); System.setProperty("convert.bson.pool.size", "128");
System.setProperty("convert.json.writer.buffer.defsize", "4096"); System.setProperty("convert.json.writer.buffer.defsize", "4096");
System.setProperty("convert.bson.writer.buffer.defsize", "4096"); System.setProperty("convert.bson.writer.buffer.defsize", "4096");
<properties>节点下也可包含非<property>节点,其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
--> -->
<properties load="config.properties"> <properties load="config.properties">
<property name="system.property.yyyy" value="YYYYYY"/> <property name="system.property.yyyy" value="YYYYYY"/>
@@ -77,6 +79,7 @@
<property name="xxxxxx" value="XXXXXXXX"/> <property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/> <property name="xxxxxx" value="XXXXXXXX"/>
</properties> </properties>
</resources> </resources>
<!-- <!--
protocol: required server所启动的协议Redkale内置的有HTTP、SNCPSNCP使用TCP实现; protocol: required server所启动的协议Redkale内置的有HTTP、SNCPSNCP使用TCP实现;
@@ -137,7 +140,7 @@
includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
--> -->
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="false" autoload="true" includes="" excludes=""> <rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes="">
<!-- <!--
value: Service类名列出的表示必须被加载的Service对象 value: Service类名列出的表示必须被加载的Service对象
ignore: 是否忽略设置为true则不会加载该Service对象默认值为false ignore: 是否忽略设置为true则不会加载该Service对象默认值为false

View File

@@ -16,6 +16,8 @@ java.util.logging.FileHandler.limit = 10485760
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-%u.log java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%u.log
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
#java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-error-%u.log
java.util.logging.FileHandler.append = true java.util.logging.FileHandler.append = true
#java.util.logging.ConsoleHandler.level = FINE #java.util.logging.ConsoleHandler.level = FINE

View File

@@ -6,6 +6,11 @@
<!-- 为NONE表示不启动缓存@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 --> <!-- 为NONE表示不启动缓存@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
<shared-cache-mode>NONE</shared-cache-mode> <shared-cache-mode>NONE</shared-cache-mode>
<properties> <properties>
<!--
DataSource的实现类没有设置默认为org.redkale.source.DataJdbcSource的实现使用常规基于JDBC的数据库驱动一般无需设置
-->
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
<!-- <!--
javax.persistence.jdbc.driver在JPA的值是JDBC驱动Redkale有所不同值应该是javax.sql.DataSource的子类。 javax.persistence.jdbc.driver在JPA的值是JDBC驱动Redkale有所不同值应该是javax.sql.DataSource的子类。
@@ -16,6 +21,7 @@
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
因此 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的值来识别驱动
--> -->
<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.user" value="root"/> <property name="javax.persistence.jdbc.user" value="root"/>

View File

@@ -1,4 +1,4 @@
/******************************************************************************* /** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved. * Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
* *
* This program and the accompanying materials are made available under the * This program and the accompanying materials are made available under the
@@ -12,7 +12,7 @@
* Linda DeMichiel - Java Persistence 2.1 * Linda DeMichiel - Java Persistence 2.1
* Linda DeMichiel - Java Persistence 2.0 * Linda DeMichiel - Java Persistence 2.0
* *
******************************************************************************/ ***************************************************************************** */
package javax.persistence; package javax.persistence;
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.TYPE;
@@ -28,18 +28,27 @@ import java.lang.annotation.Target;
* subclasses; it can be overridden by specifying * subclasses; it can be overridden by specifying
* <code>Cacheable</code> on a subclass. * <code>Cacheable</code> on a subclass.
* *
* <p> <code>Cacheable(false)</code> means that the entity and its state must * <p>
* <code>Cacheable(false)</code> means that the entity and its state must
* not be cached by the provider. * not be cached by the provider.
* *
* @since Java Persistence 2.0 * @since Java Persistence 2.0
*/ */
@Target( { TYPE }) @Target({TYPE})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Cacheable { public @interface Cacheable {
/** /**
* (Optional) Whether or not the entity should be cached. * (Optional) Whether or not the entity should be cached.
*
* @return boolean * @return boolean
*/ */
boolean value() default true; boolean value() default true;
/**
* (Optional) 定时自动更新缓存的周期秒数为0表示不做定时更新 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
*
* @return int
*/
int interval() default 0;
} }

View File

@@ -0,0 +1,69 @@
/** *****************************************************************************
* Copyright (c) 2011 - 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
*
***************************************************************************** */
package javax.persistence;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Used in schema generation to specify creation of an index.
* <p>
* Note that it is not necessary to specify an index for a primary key,
* as the primary key index will be created automatically.
*
* <p>
* The syntax of the <code>columnList</code> element is a
* <code>column_list</code>, as follows:
*
* <pre>
* column::= index_column [,index_column]*
* index_column::= column_name [ASC | DESC]
* </pre>
*
* <p>
* If <code>ASC</code> or <code>DESC</code> is not specified,
* <code>ASC</code> (ascending order) is assumed.
*
* @since Java Persistence 2.1
*
*/
@Target({})
@Retention(RUNTIME)
public @interface Index {
/**
* (Optional) The name of the index; defaults to a provider-generated name.
*
* @return String
*/
String name() default "";
/**
* (Required) The names of the columns to be included in the index,
* in order.
*
* @return String
*/
String columnList();
/**
* (Optional) Whether the index is unique.
*
* @return boolean
*/
boolean unique() default false;
}

View File

@@ -59,4 +59,29 @@ public @interface Table {
*/ */
String catalog() default ""; String catalog() default "";
/**
* (Optional) Unique constraints that are to be placed on
* the table. These are only used if table generation is in
* effect. These constraints apply in addition to any constraints
* specified by the <code>Column</code> and <code>JoinColumn</code>
* annotations and constraints entailed by primary key mappings.
* <p>
* Defaults to no additional constraints.
* @return UniqueConstraint[]
*/
UniqueConstraint[] uniqueConstraints() default {};
/**
* (Optional) Indexes for the table. These are only used if
* table generation is in effect. Note that it is not necessary
* to specify an index for a primary key, as the primary key
* index will be created automatically.
*
* @return indexes
* @since Java Persistence 2.1
*/
Index[] indexes() default {};
String comment() default "";
} }

View File

@@ -0,0 +1,56 @@
/** *****************************************************************************
* 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.RetentionPolicy.RUNTIME;
/**
* Specifies that a unique constraint is to be included in
* the generated DDL for a primary or secondary table.
*
* <pre>
* Example:
* &#064;Entity
* &#064;Table(
* name="EMPLOYEE",
* uniqueConstraints=
* &#064;UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})
* )
* public class Employee { ... }
* </pre>
*
* @since Java Persistence 1.0
*/
@Target({})
@Retention(RUNTIME)
public @interface UniqueConstraint {
/** (Optional) Constraint name. A provider-chosen name will be chosen
* if a name is not specified.
*
* @return String
* @since Java Persistence 2.0
*/
String name() default "";
/** (Required) An array of the column names that make up the constraint.
*
* @return String[]
*/
String[] columnNames();
}

View File

@@ -8,21 +8,24 @@ package org.redkale.boot;
import java.io.*; import java.io.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import javax.persistence.Column; import javax.persistence.*;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.source.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 继承 HttpBaseServlet 是为了获取 WebAction 信息 * API接口文档生成类作用生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
* 继承 HttpBaseServlet 是为了获取 WebMapping 信息
* *
* <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public class ApiDocs extends HttpBaseServlet { public class ApiDocs extends HttpBaseServlet {
private final Application app; private final Application app; //Application全局对象
public ApiDocs(Application app) { public ApiDocs(Application app) {
this.app = app; this.app = app;
@@ -31,7 +34,7 @@ public class ApiDocs extends HttpBaseServlet {
public void run() throws Exception { public void run() throws Exception {
List<Map> serverList = new ArrayList<>(); List<Map> serverList = new ArrayList<>();
Map<String, Map<String, Map<String, String>>> typesmap = new LinkedHashMap<>(); Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
for (NodeServer node : app.servers) { for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue; if (!(node instanceof NodeHttpServer)) continue;
final Map<String, Object> map = new LinkedHashMap<>(); final Map<String, Object> map = new LinkedHashMap<>();
@@ -49,82 +52,136 @@ public class ApiDocs extends HttpBaseServlet {
} }
final Map<String, Object> servletmap = new LinkedHashMap<>(); final Map<String, Object> servletmap = new LinkedHashMap<>();
String prefix = _prefix(servlet); String prefix = _prefix(servlet);
String[] mappings = ws.value(); String[] urlregs = ws.value();
if (prefix != null && !prefix.isEmpty()) { if (prefix != null && !prefix.isEmpty()) {
for (int i = 0; i < mappings.length; i++) { for (int i = 0; i < urlregs.length; i++) {
mappings[i] = prefix + mappings[i]; urlregs[i] = prefix + urlregs[i];
} }
} }
servletmap.put("mappings", mappings); servletmap.put("urlregs", urlregs);
servletmap.put("moduleid", ws.moduleid()); servletmap.put("moduleid", ws.moduleid());
servletmap.put("name", ws.name()); servletmap.put("name", ws.name());
servletmap.put("comment", ws.comment()); servletmap.put("comment", ws.comment());
List<Map> actionsList = new ArrayList<>(); List<Map> mappingsList = new ArrayList<>();
servletmap.put("actions", actionsList); servletmap.put("mappings", mappingsList);
for (Method method : servlet.getClass().getMethods()) { final Class selfClz = servlet.getClass();
if (method.getParameterCount() != 2) continue; Class clz = servlet.getClass();
WebAction action = method.getAnnotation(WebAction.class); HashSet<String> actionurls = new HashSet<>();
if (action == null) continue; do {
final Map<String, Object> actionmap = new LinkedHashMap<>(); if (Modifier.isAbstract(clz.getModifiers())) break;
actionmap.put("url", prefix + action.url()); for (Method method : clz.getMethods()) {
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null); if (method.getParameterCount() != 2) continue;
actionmap.put("actionid", action.actionid()); WebMapping action = method.getAnnotation(WebMapping.class);
actionmap.put("comment", action.comment()); if (action == null) continue;
List<Map> paramsList = new ArrayList<>(); if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
actionmap.put("params", paramsList); final Map<String, Object> mappingmap = new LinkedHashMap<>();
for (WebParam param : method.getAnnotationsByType(WebParam.class)) { if (actionurls.contains(action.url())) continue;
final Map<String, Object> parammap = new LinkedHashMap<>(); mappingmap.put("url", prefix + action.url());
final boolean isarray = param.type().isArray(); actionurls.add(action.url());
final Class ptype = isarray ? param.type().getComponentType() : param.type(); mappingmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
parammap.put("name", param.name()); mappingmap.put("actionid", action.actionid());
parammap.put("radix", param.radix()); mappingmap.put("comment", action.comment());
parammap.put("type", ptype.getName() + (isarray ? "[]" : "")); List<Map> paramsList = new ArrayList<>();
parammap.put("src", param.src()); mappingmap.put("params", paramsList);
parammap.put("comment", param.comment()); List<String> results = new ArrayList<>();
paramsList.add(parammap); for (final Class rtype : action.results()) {
if (ptype.isPrimitive() || ptype == String.class) continue; results.add(rtype.getName());
if (typesmap.containsKey(ptype.getName())) continue; if (typesmap.containsKey(rtype.getName())) continue;
final boolean filter = FilterBean.class.isAssignableFrom(rtype);
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = rtype;
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
final Map<String, Map<String, String>> typemap = new LinkedHashMap<>(); Map<String, Object> fieldmap = new LinkedHashMap<>();
Class loop = ptype; fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, String> fieldmap = new LinkedHashMap<>(); Comment comment = field.getAnnotation(Comment.class);
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else {
Column col = field.getAnnotation(Column.class); Column col = field.getAnnotation(Column.class);
if (col != null) fieldmap.put("comment", col.comment()); FilterColumn fc = field.getAnnotation(FilterColumn.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
typemap.put(field.getName(), fieldmap);
} }
} while ((loop = loop.getSuperclass()) != Object.class);
typesmap.put(rtype.getName(), typemap);
}
mappingmap.put("results", results);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type();
parammap.put("name", param.name());
parammap.put("radix", param.radix());
parammap.put("type", ptype.getName() + (isarray ? "[]" : ""));
parammap.put("src", param.src());
parammap.put("comment", param.comment());
parammap.put("required", param.required());
paramsList.add(parammap);
if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesmap.containsKey(ptype.getName())) continue;
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) { final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
if (field.getAnnotation(RestAddress.class) != null) continue; Class loop = ptype;
final boolean filter = FilterBean.class.isAssignableFrom(loop);
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Column col = field.getAnnotation(Column.class);
FilterColumn fc = field.getAnnotation(FilterColumn.class);
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
typemap.put(field.getName(), fieldmap);
} }
} while ((loop = loop.getSuperclass()) != Object.class);
typemap.put(field.getName(), fieldmap); typesmap.put(ptype.getName(), typemap);
} }
} while ((loop = loop.getSuperclass()) != Object.class); mappingmap.put("result", action.result());
mappingsList.add(mappingmap);
typesmap.put(ptype.getName(), typemap);
} }
actionmap.put("result", action.result()); } while ((clz = clz.getSuperclass()) != HttpServlet.class);
actionsList.add(actionmap); mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
}
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletmap); servletsList.add(servletmap);
} }
servletsList.sort((o1, o2) -> { servletsList.sort((o1, o2) -> {
String[] mappings1 = (String[]) o1.get("mappings"); String[] urlregs1 = (String[]) o1.get("urlregs");
String[] mappings2 = (String[]) o2.get("mappings"); String[] urlregs2 = (String[]) o2.get("urlregs");
return mappings1.length > 0 ? (mappings2.length > 0 ? mappings1[0].compareTo(mappings2[0]) : 1) : -1; return urlregs1.length > 0 ? (urlregs2.length > 0 ? urlregs1[0].compareTo(urlregs2[0]) : 1) : -1;
}); });
} }
Map<String, Object> resultmap = new LinkedHashMap<>(); Map<String, Object> resultmap = new LinkedHashMap<>();
@@ -140,7 +197,7 @@ public class ApiDocs extends HttpBaseServlet {
in = new FileInputStream(doctemplate); in = new FileInputStream(doctemplate);
} }
if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html"); if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html");
String content = Utility.read(in).replace("${content}", json); String content = Utility.read(in).replace("'${content}'", json);
in.close(); in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html")); FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes("UTF-8")); outhtml.write(content.getBytes("UTF-8"));
@@ -148,7 +205,7 @@ public class ApiDocs extends HttpBaseServlet {
} }
@Override @Override
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException { public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
return true; next.execute(request, response);
} }
} }

View File

@@ -30,9 +30,17 @@ import org.redkale.watch.WatchFactory;
import org.w3c.dom.*; import org.w3c.dom.*;
/** /**
* 编译时需要加入: -XDignore.symbol.file=true *
* 进程启动类,全局对象。 <br>
* <pre>
* 程序启动执行步骤:
* 1、读取application.xml
* 2、进行classpath扫描动态加载Service与Servlet
* 3、优先加载所有SNCP协议的服务再加载其他协议服务
* 4、最后进行Service、Servlet与其他资源之间的依赖注入
* </pre>
* <p> * <p>
* 进程启动类程序启动后读取application.xml,进行classpath扫描动态加载Service与Servlet 优先加载所有SNCP协议的服务 再加载其他协议服务, 最后进行Service、Servlet与其他资源之间的依赖注入。 * 编译时需要加入: -XDignore.symbol.file=true
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -40,65 +48,99 @@ import org.w3c.dom.*;
*/ */
public final class Application { public final class Application {
//当前进程启动的时间, 类型: long /**
* 当前进程启动的时间, 类型: long
*/
public static final String RESNAME_APP_TIME = "APP_TIME"; public static final String RESNAME_APP_TIME = "APP_TIME";
//当前进程的根目录, 类型String、File、Path /**
* 当前进程的根目录, 类型String、File、Path
*/
public static final String RESNAME_APP_HOME = "APP_HOME"; public static final String RESNAME_APP_HOME = "APP_HOME";
//application.xml 文件中resources节点的内容 类型: AnyValue /**
* application.xml 文件中resources节点的内容 类型: AnyValue
*/
public static final String RESNAME_APP_GRES = "APP_GRES"; public static final String RESNAME_APP_GRES = "APP_GRES";
//当前进程节点的name 类型String /**
* 当前进程节点的name 类型String
*/
public static final String RESNAME_APP_NODE = "APP_NODE"; public static final String RESNAME_APP_NODE = "APP_NODE";
//当前进程节点的IP地址 类型InetAddress、String /**
* 当前进程节点的IP地址 类型InetAddress、String
*/
public static final String RESNAME_APP_ADDR = "APP_ADDR"; public static final String RESNAME_APP_ADDR = "APP_ADDR";
//当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String /**
* 当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
*/
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR"; public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR";
//当前SNCP Server所属的组 类型: String /**
* 当前SNCP Server所属的组 类型: String
*/
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP"; public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP";
//当前Server的ROOT目录 类型String、File、Path /**
* 当前Server的ROOT目录 类型String、File、Path
*/
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT; public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
//每个地址对应的Group名
final Map<InetSocketAddress, String> globalNodes = new HashMap<>(); final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
//协议地址的Group集合
final Map<String, GroupInfo> globalGroups = new HashMap<>(); final Map<String, GroupInfo> globalGroups = new HashMap<>();
//本地IP地址
final InetAddress localAddress; final InetAddress localAddress;
//CacheSource 资源
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>(); final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
//DataSource 资源
final List<DataSource> dataSources = new CopyOnWriteArrayList<>(); final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
//NodeServer 资源
final List<NodeServer> servers = new CopyOnWriteArrayList<>(); final List<NodeServer> servers = new CopyOnWriteArrayList<>();
//传输端的ByteBuffer对象池
final ObjectPool<ByteBuffer> transportBufferPool; final ObjectPool<ByteBuffer> transportBufferPool;
//传输端的线程池
final ExecutorService transportExecutor; final ExecutorService transportExecutor;
//传输端的ChannelGroup
final AsynchronousChannelGroup transportChannelGroup; final AsynchronousChannelGroup transportChannelGroup;
//全局根ResourceFactory
final ResourceFactory resourceFactory = ResourceFactory.root(); final ResourceFactory resourceFactory = ResourceFactory.root();
//服务配置项
final AnyValue config;
//临时计数器
CountDownLatch servicecdl; //会出现两次赋值 CountDownLatch servicecdl; //会出现两次赋值
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
//是否用于main方法运行
private final boolean singletonrun; private final boolean singletonrun;
//根WatchFactory
private final WatchFactory watchFactory = WatchFactory.root(); private final WatchFactory watchFactory = WatchFactory.root();
//进程根目录
private final File home; private final File home;
//日志
private final Logger logger; private final Logger logger;
private final AnyValue config; //服务启动时间
private final long startTime = System.currentTimeMillis(); private final long startTime = System.currentTimeMillis();
//Server启动的计数器用于确保所有Server都启动完后再进行下一步处理
private final CountDownLatch serversLatch; private final CountDownLatch serversLatch;
private Application(final AnyValue config) { private Application(final AnyValue config) {
@@ -164,7 +206,8 @@ public final class Application {
Properties prop = new Properties(); Properties prop = new Properties();
final String handlers = properties.getProperty("handlers"); final String handlers = properties.getProperty("handlers");
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) { if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", fileHandlerClass)); //singletonrun模式下不输出文件日志
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", singletonrun ? "" : fileHandlerClass));
} }
if (!prop.isEmpty()) { if (!prop.isEmpty()) {
String prefix = fileHandlerClass + "."; String prefix = fileHandlerClass + ".";
@@ -189,6 +232,7 @@ public final class Application {
} }
this.logger = Logger.getLogger(this.getClass().getSimpleName()); this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1); this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
logger.log(Level.INFO, "------------------------------- Redkale -------------------------------");
//------------------配置 <transport> 节点 ------------------ //------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null; ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null; ExecutorService transportExec = null;
@@ -263,7 +307,7 @@ public final class Application {
File persist = new File(this.home, "conf/persistence.xml"); File persist = new File(this.home, "conf/persistence.xml");
final String homepath = this.home.getCanonicalPath(); final String homepath = this.home.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataDefaultSource.DATASOURCE_CONFPATH, persist.getCanonicalPath()); if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
logger.log(Level.INFO, RESNAME_APP_HOME + "= " + homepath + "\r\n" + RESNAME_APP_ADDR + "= " + this.localAddress.getHostAddress()); logger.log(Level.INFO, RESNAME_APP_HOME + "= " + homepath + "\r\n" + RESNAME_APP_ADDR + "= " + this.localAddress.getHostAddress());
String lib = config.getValue("lib", "").trim().replace("${APP_HOME}", homepath); String lib = config.getValue("lib", "").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf"); lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
@@ -294,6 +338,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}", home.getCanonicalPath()).replace('\\', '/');
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.")) {
@@ -306,11 +351,6 @@ public final class Application {
} }
} }
} }
if (this.localAddress != null && this.resourceFactory.find("property.datasource.nodeid", String.class) == null) {
byte[] bs = this.localAddress.getAddress();
int v = (0xff & bs[bs.length - 2]) % 10 * 100 + (0xff & bs[bs.length - 1]);
this.resourceFactory.register("property.datasource.nodeid", "" + v);
}
this.resourceFactory.register(BsonFactory.root()); this.resourceFactory.register(BsonFactory.root());
this.resourceFactory.register(JsonFactory.root()); this.resourceFactory.register(JsonFactory.root());
this.resourceFactory.register(BsonFactory.root().getConvert()); this.resourceFactory.register(BsonFactory.root().getConvert());
@@ -332,7 +372,7 @@ public final class Application {
} }
GroupInfo ginfo = globalGroups.get(group); GroupInfo ginfo = globalGroups.get(group);
if (ginfo == null) { if (ginfo == null) {
ginfo = new GroupInfo(group, protocol, conf.getValue("kind", ""), new LinkedHashSet<>()); ginfo = new GroupInfo(group, protocol, conf.getValue("subprotocol", ""), new LinkedHashSet<>());
globalGroups.put(group, ginfo); globalGroups.put(group, ginfo);
} }
for (AnyValue node : conf.getAnyValues("node")) { for (AnyValue node : conf.getAnyValues("node")) {
@@ -422,13 +462,27 @@ public final class Application {
channel.write(buffer); channel.write(buffer);
buffer.clear(); buffer.clear();
channel.configureBlocking(false); channel.configureBlocking(false);
channel.read(buffer); try {
buffer.flip(); channel.read(buffer);
byte[] bytes = new byte[buffer.remaining()]; buffer.flip();
buffer.get(bytes); byte[] bytes = new byte[buffer.remaining()];
channel.close(); buffer.get(bytes);
logger.info(new String(bytes)); channel.close();
Thread.sleep(500); logger.info(new String(bytes));
Thread.sleep(500);
} catch (Exception e) {
if (e instanceof PortUnreachableException) {
if ("APIDOC".equalsIgnoreCase(command)) {
final Application application = Application.create(true);
application.init();
application.start();
new ApiDocs(application).run();
logger.info("APIDOC OK");
return;
}
}
throw e;
}
} }
public void start() throws Exception { public void start() throws Exception {
@@ -462,7 +516,7 @@ public final class Application {
for (final AnyValue serconf : serconfs) { for (final AnyValue serconf : serconfs) {
Thread thread = new Thread() { Thread thread = new Thread() {
{ {
String host = serconf.getValue("host", "").replace("0.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(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
this.setDaemon(true); this.setDaemon(true);
} }

View File

@@ -28,9 +28,9 @@ import org.redkale.util.AnyValue.DefaultAnyValue;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class ClassFilter<T> { 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 finer = logger.isLoggable(Level.FINER); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果 private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果

View File

@@ -7,8 +7,10 @@ package org.redkale.boot;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.*; import java.util.*;
import org.redkale.convert.json.JsonConvert;
/** /**
* 协议地址组合对象, 对应application.xml 中 resources-&#62;group 节点信息
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -17,21 +19,21 @@ import java.util.*;
*/ */
public class GroupInfo { public class GroupInfo {
protected String name; protected String name; //地址
protected String protocol; protected String protocol; //协议 取值范围: TCP、UDP
protected String kind; protected String subprotocol; //子协议,预留使用
protected Set<InetSocketAddress> addrs; protected Set<InetSocketAddress> addrs; //地址列表, 对应 resources-&#62;group-&#62;node节点信息
public GroupInfo() { public GroupInfo() {
} }
public GroupInfo(String name, String protocol, String kind, Set<InetSocketAddress> addrs) { public GroupInfo(String name, String protocol, String subprotocol, Set<InetSocketAddress> addrs) {
this.name = name; this.name = name;
this.protocol = protocol; this.protocol = protocol;
this.kind = kind; this.subprotocol = subprotocol;
this.addrs = addrs; this.addrs = addrs;
} }
@@ -51,12 +53,12 @@ public class GroupInfo {
this.protocol = protocol; this.protocol = protocol;
} }
public String getKind() { public String getSubprotocol() {
return kind; return subprotocol;
} }
public void setKind(String kind) { public void setSubprotocol(String subprotocol) {
this.kind = kind; this.subprotocol = subprotocol;
} }
public Set<InetSocketAddress> getAddrs() { public Set<InetSocketAddress> getAddrs() {
@@ -71,4 +73,8 @@ public class GroupInfo {
this.addrs = addrs; this.addrs = addrs;
} }
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
} }

View File

@@ -70,12 +70,12 @@ public class LogFileHandler extends Handler {
throwable = sw.toString(); throwable = sw.toString();
} }
return String.format(format, return String.format(format,
System.currentTimeMillis(), System.currentTimeMillis(),
source, source,
record.getLoggerName(), record.getLoggerName(),
record.getLevel().getName(), record.getLevel().getName(),
message, message,
throwable); throwable);
} }
} }
@@ -84,9 +84,13 @@ public class LogFileHandler extends Handler {
private String pattern; private String pattern;
private String unusual; //不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中
private int limit; //文件大小限制 private int limit; //文件大小限制
private final AtomicInteger index = new AtomicInteger(); private final AtomicInteger logindex = new AtomicInteger();
private final AtomicInteger logunusualindex = new AtomicInteger();
private int count = 1; //文件限制 private int count = 1; //文件限制
@@ -94,11 +98,17 @@ public class LogFileHandler extends Handler {
private boolean append; private boolean append;
private final AtomicLong length = new AtomicLong(); private final AtomicLong loglength = new AtomicLong();
private final AtomicLong logunusuallength = new AtomicLong();
private File logfile; private File logfile;
private OutputStream stream; private File logunusualfile;
private OutputStream logstream;
private OutputStream logunusualstream;
public LogFileHandler() { public LogFileHandler() {
updateTomorrow(); updateTomorrow();
@@ -114,7 +124,7 @@ public class LogFileHandler extends Handler {
cal.set(Calendar.MILLISECOND, 0); cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.DAY_OF_YEAR, 1); cal.add(Calendar.DAY_OF_YEAR, 1);
long t = cal.getTimeInMillis(); long t = cal.getTimeInMillis();
if (this.tomorrow != t) index.set(0); if (this.tomorrow != t) logindex.set(0);
this.tomorrow = t; this.tomorrow = t;
} }
@@ -131,35 +141,59 @@ public class LogFileHandler extends Handler {
while (true) { while (true) {
try { try {
LogRecord record = records.take(); LogRecord record = records.take();
final boolean bigger = (limit > 0 && limit <= length.get()); final boolean bigger = (limit > 0 && limit <= loglength.get());
if (bigger || tomorrow <= record.getMillis()) { final boolean changeday = tomorrow <= record.getMillis();
if (bigger || changeday) {
updateTomorrow(); updateTomorrow();
if (stream != null) { if (logstream != null) {
stream.close(); logstream.close();
if (bigger) { if (bigger) {
for (int i = Math.min(count - 2, index.get() - 1); i > 0; i--) { for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) {
File greater = new File(logfile.getPath() + "." + i); File greater = new File(logfile.getPath() + "." + i);
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} }
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} }
stream = null; logstream = null;
} }
} }
if (stream == null) { if (unusual != null && changeday && logunusualstream != null) {
index.incrementAndGet(); logunusualstream.close();
if (limit > 0 && limit <= logunusuallength.get()) {
for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) {
File greater = new File(logunusualfile.getPath() + "." + i);
if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
logunusualstream = null;
}
if (logstream == null) {
logindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now(); java.time.LocalDate date = LocalDate.now();
logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth())))); logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logfile.getParentFile().mkdirs(); logfile.getParentFile().mkdirs();
length.set(logfile.length()); loglength.set(logfile.length());
stream = new FileOutputStream(logfile, append); logstream = new FileOutputStream(logfile, append);
}
if (unusual != null && logunusualstream == null) {
logunusualindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now();
logunusualfile = new File(unusual.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logunusualfile.getParentFile().mkdirs();
logunusuallength.set(logunusualfile.length());
logunusualstream = new FileOutputStream(logunusualfile, append);
} }
//----------------------写日志------------------------- //----------------------写日志-------------------------
String message = getFormatter().format(record); String message = getFormatter().format(record);
String encoding = getEncoding(); String encoding = getEncoding();
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding); byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
stream.write(bytes); logstream.write(bytes);
length.addAndGet(bytes.length); loglength.addAndGet(bytes.length);
if (unusual != null && (record.getLevel() == Level.WARNING || record.getLevel() == Level.SEVERE)) {
logunusualstream.write(bytes);
logunusuallength.addAndGet(bytes.length);
}
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE); if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE);
@@ -177,30 +211,39 @@ public class LogFileHandler extends Handler {
private void configure() { private void configure() {
LogManager manager = LogManager.getLogManager(); LogManager manager = LogManager.getLogManager();
String cname = LogFileHandler.class.getName(); String cname = LogFileHandler.class.getName();
pattern = manager.getProperty(cname + ".pattern"); this.pattern = manager.getProperty(cname + ".pattern");
if (pattern == null) { if (this.pattern == null) {
pattern = "logs-%m/" + getPrefix() + "log-%d.log"; this.pattern = "logs-%m/" + getPrefix() + "log-%d.log";
} else { } else {
int pos = pattern.lastIndexOf('/'); int pos = this.pattern.lastIndexOf('/');
if (pos > 0) { if (pos > 0) {
pattern = pattern.substring(0, pos + 1) + getPrefix() + pattern.substring(pos + 1); this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1);
} else { } else {
pattern = getPrefix() + pattern; this.pattern = getPrefix() + this.pattern;
}
}
String unusualstr = manager.getProperty(cname + ".unusual");
if (unusualstr != null) {
int pos = unusualstr.lastIndexOf('/');
if (pos > 0) {
this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1);
} else {
this.unusual = getPrefix() + unusualstr;
} }
} }
String limitstr = manager.getProperty(cname + ".limit"); String limitstr = manager.getProperty(cname + ".limit");
try { try {
if (limitstr != null) limit = Math.abs(Integer.decode(limitstr)); if (limitstr != null) this.limit = Math.abs(Integer.decode(limitstr));
} catch (Exception e) { } catch (Exception e) {
} }
String countstr = manager.getProperty(cname + ".count"); String countstr = manager.getProperty(cname + ".count");
try { try {
if (countstr != null) count = Math.max(1, Math.abs(Integer.decode(countstr))); if (countstr != null) this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
} catch (Exception e) { } catch (Exception e) {
} }
String appendstr = manager.getProperty(cname + ".append"); String appendstr = manager.getProperty(cname + ".append");
try { try {
if (appendstr != null) append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr); if (appendstr != null) this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
} catch (Exception e) { } catch (Exception e) {
} }
String levelstr = manager.getProperty(cname + ".level"); String levelstr = manager.getProperty(cname + ".level");
@@ -256,7 +299,7 @@ public class LogFileHandler extends Handler {
@Override @Override
public void flush() { public void flush() {
try { try {
if (stream != null) stream.flush(); if (logstream != null) logstream.flush();
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE); if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE);
@@ -266,7 +309,7 @@ public class LogFileHandler extends Handler {
@Override @Override
public void close() throws SecurityException { public void close() throws SecurityException {
try { try {
if (stream != null) stream.close(); if (logstream != null) logstream.close();
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE); if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE);

View File

@@ -29,7 +29,7 @@ import org.redkale.util.*;
@NodeProtocol({"HTTP"}) @NodeProtocol({"HTTP"})
public class NodeHttpServer extends NodeServer { public class NodeHttpServer extends NodeServer {
protected final boolean rest; protected final boolean rest; //是否加载REST服务 为true加载rest节点信息并将所有可REST化的Service生成RestHttpServlet
protected final HttpServer httpServer; protected final HttpServer httpServer;
@@ -74,7 +74,7 @@ public class NodeHttpServer extends NodeServer {
synchronized (regFactory) { synchronized (regFactory) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class); Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (nodeService == null) { if (nodeService == null) {
nodeService = Sncp.createLocalService(resourceName, getExecutor(), application.getResourceFactory(), WebSocketNodeService.class, (InetSocketAddress) null, (Transport) null, (Collection<Transport>) null); nodeService = Sncp.createLocalService(resourceName, getExecutor(), application.getResourceFactory(), WebSocketNodeService.class, (InetSocketAddress) null, (String) null, (Set<String>) null, (AnyValue) null, (Transport) null, (Collection<Transport>) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService); regFactory.register(resourceName, WebSocketNode.class, nodeService);
resourceFactory.inject(nodeService, self); resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService); logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
@@ -109,13 +109,6 @@ public class NodeHttpServer extends NodeServer {
final String[] mappings = ws.value(); final String[] mappings = ws.value();
String pref = ws.repair() ? prefix : ""; String pref = ws.repair() ? prefix : "";
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty(); DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
WebInitParam[] webparams = ws.initParams();
if (webparams.length > 0) {
if (servletConf == null) servletConf = new DefaultAnyValue();
for (WebInitParam webparam : webparams) {
servletConf.addValue(webparam.name(), webparam.value());
}
}
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings); this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
if (ss != null) { if (ss != null) {
for (int i = 0; i < mappings.length; i++) { for (int i = 0; i < mappings.length; i++) {
@@ -124,32 +117,31 @@ public class NodeHttpServer extends NodeServer {
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings)); ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings));
} }
} }
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())); Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
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();
} }
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Loaded ").append(as.getKey()); sb.append(threadName).append(" Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) { for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' '); sb.append(' ');
} }
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR); sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
} }
} }
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
if (rest && serverConf != null) { if (rest && serverConf != null) {
for (AnyValue restConf : serverConf.getAnyValues("rest")) { for (AnyValue restConf : serverConf.getAnyValues("rest")) {
loadRestServlet(prefix, restConf); loadRestServlet(prefix, restConf, sb);
} }
} }
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
} }
protected void loadRestServlet(final String prefix, final AnyValue restConf) throws Exception { protected void loadRestServlet(final String prefix, final AnyValue restConf, final StringBuilder sb) throws Exception {
if (!rest) return; if (!rest) return;
if (restConf == null) return; //不存在REST服务 if (restConf == null) return; //不存在REST服务
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] "; final String threadName = "[" + Thread.currentThread().getName() + "] ";
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>(); final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
@@ -170,8 +162,9 @@ public class NodeHttpServer extends NodeServer {
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues); final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
super.interceptorServiceWrappers.forEach((wrapper) -> { super.interceptorServices.forEach((service) -> {
final Class stype = wrapper.getType(); final Class stype = Sncp.getServiceType(service);
final String name = Sncp.getResourceName(service);
RestService rs = (RestService) stype.getAnnotation(RestService.class); RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs != null && rs.ignore()) return; if (rs != null && rs.ignore()) return;
if (mustsign && rs == null) return; if (mustsign && rs == null) return;
@@ -181,17 +174,15 @@ public class NodeHttpServer extends NodeServer {
if (!autoload && !includeValues.contains(stypename)) return; if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return; if (!restFilter.accept(stypename)) return;
RestHttpServlet servlet = httpServer.addRestServlet(wrapper.getName(), stype, wrapper.getService(), baseServletClass, prefix, (AnyValue) null); RestHttpServlet servlet = httpServer.addRestServlet(name, stype, service, baseServletClass, prefix, (AnyValue) null);
resourceFactory.inject(servlet, NodeHttpServer.this); resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest("Create RestServlet[resource=" + wrapper.getName() + "] = " + 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] = prefix + mappings[i]; mappings[i] = prefix + mappings[i];
} }
if (servlet.getClass().getSimpleName().charAt(0) != '_') { ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
}
} }
}); });
//输出信息 //输出信息
@@ -201,14 +192,14 @@ public class NodeHttpServer extends NodeServer {
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();
} }
sb.append(threadName).append(" ").append(LINE_SEPARATOR);
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Loaded ").append(as.getKey()); sb.append(threadName).append(" Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) { for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' '); sb.append(' ');
} }
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR); sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
} }
} }
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
} }
} }

View File

@@ -5,10 +5,8 @@
*/ */
package org.redkale.boot; package org.redkale.boot;
import java.util.Objects;
import org.redkale.service.Service;
/** /**
* NodeServer的拦截类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -17,71 +15,24 @@ import org.redkale.service.Service;
*/ */
public class NodeInterceptor { public class NodeInterceptor {
/** *
* Server.start之前调用 <br>
* NodeServer.start的部署是先执行NodeInterceptor.preStart再执行 Server.start 方法
*
* @param server NodeServer
*/
public void preStart(NodeServer server) { public void preStart(NodeServer server) {
} }
/**
* Server.shutdown之前调用 <br>
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown再执行 Server.sshutdown 方法
*
* @param server NodeServer
*/
public void preShutdown(NodeServer server) { public void preShutdown(NodeServer server) {
} }
public static class InterceptorServiceWrapper<T extends Service> {
private String name;
private Class<T> type;
private T service;
public InterceptorServiceWrapper() {
}
public InterceptorServiceWrapper(String name, Class<T> type, T service) {
this.name = name;
this.type = type;
this.service = service;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class<T> getType() {
return type;
}
public void setType(Class<T> type) {
this.type = type;
}
public T getService() {
return service;
}
public void setService(T service) {
this.service = service;
}
@Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + Objects.hashCode(this.name);
hash = 97 * hash + Objects.hashCode(this.type);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final InterceptorServiceWrapper<?> other = (InterceptorServiceWrapper<?>) obj;
return Objects.equals(this.name, other.name) && Objects.equals(this.type, other.type);
}
}
} }

View File

@@ -8,7 +8,7 @@ package org.redkale.boot;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑 * 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑, 只能注解在NodeServer子类上
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -69,7 +69,7 @@ public abstract class NodeServer {
private InetSocketAddress sncpAddress; private InetSocketAddress sncpAddress;
//加载Service时的处理函数 //加载Service时的处理函数
protected Consumer<ServiceWrapper> consumer; protected Consumer<Service> consumer;
//server节点的配置 //server节点的配置
protected AnyValue serverConf; protected AnyValue serverConf;
@@ -78,13 +78,17 @@ public abstract class NodeServer {
protected NodeInterceptor interceptor; protected NodeInterceptor interceptor;
//供interceptor使用的Service对象集合 //供interceptor使用的Service对象集合
protected final Set<NodeInterceptor.InterceptorServiceWrapper> interceptorServiceWrappers = new LinkedHashSet<>(); protected final Set<Service> interceptorServices = new LinkedHashSet<>();
//本地模式的Service对象集合 //本地模式的Service对象集合
protected final Set<ServiceWrapper> localServiceWrappers = new LinkedHashSet<>(); protected final Set<Service> localServices = new LinkedHashSet<>();
//远程模式的Service对象集合 //远程模式的Service对象集合
protected final Set<ServiceWrapper> remoteServiceWrappers = new LinkedHashSet<>(); protected final Set<Service> remoteServices = new LinkedHashSet<>();
private volatile int maxClassNameLength = 0;
private volatile int maxNameLength = 0;
public NodeServer(Application application, Server server) { public NodeServer(Application application, Server server) {
this.application = application; this.application = application;
@@ -116,7 +120,7 @@ public abstract class NodeServer {
if (context == null) { if (context == null) {
t.run(); t.run();
} else { } else {
context.submit(t); context.submitAsync(t);
} }
} }
@@ -191,11 +195,36 @@ public abstract class NodeServer {
final NodeServer self = this; final NodeServer self = this;
//--------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory(); final ResourceFactory appResFactory = application.getResourceFactory();
//------------------------------------- 注册Resource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
Resource res = field.getAnnotation(Resource.class);
if (res == null || !res.name().startsWith("properties.")) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
Class type = field.getType();
if (type != AnyValue.class && type != AnyValue[].class) return;
Object resource = null;
final AnyValue resources = application.config.getAnyValue("resources");
final AnyValue properties = resources == null ? null : resources.getAnyValue("properties");
if (properties != null && type == AnyValue.class) {
resource = properties.getAnyValue(res.name().substring("properties.".length()));
appResFactory.register(resourceName, AnyValue.class, resource);
} else if (properties != null && type == AnyValue[].class) {
resource = properties.getAnyValues(res.name().substring("properties.".length()));
appResFactory.register(resourceName, AnyValue[].class, resource);
}
field.set(src, resource);
} catch (Exception e) {
logger.log(Level.SEVERE, "Resource inject error", e);
}
}, AnyValue.class, AnyValue[].class);
//------------------------------------- 注册DataSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { resourceFactory.register((ResourceFactory rf, final Object src, 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) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
DataSource source = new DataDefaultSource(resourceName); DataSource source = DataSources.createDataSource(resourceName);
application.dataSources.add(source); application.dataSources.add(source);
appResFactory.register(resourceName, DataSource.class, source); appResFactory.register(resourceName, DataSource.class, source);
@@ -204,33 +233,34 @@ public abstract class NodeServer {
List<Transport> diffGroupTransports = Arrays.asList(Sncp.getDiffGroupTransports((Service) src)); List<Transport> diffGroupTransports = Arrays.asList(Sncp.getDiffGroupTransports((Service) src));
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, DataCacheListenerService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr); final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports); Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpServer.getSncpGroup(), gs, null); Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, DataCacheListenerService.class, sncpAddr, sncpServer.getSncpGroup(), gs, Sncp.getConf((Service) src), sameGroupTransport, diffGroupTransports);
localServiceWrappers.add(wrapper); appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
sncpServer.consumerAccept(wrapper); localServices.add(cacheListenerService);
sncpServer.consumerAccept(cacheListenerService);
rf.inject(cacheListenerService, self); rf.inject(cacheListenerService, self);
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService()); logger.info("[" + Thread.currentThread().getName() + "] Load Service " + cacheListenerService);
} }
field.set(src, source); field.set(src, source);
rf.inject(source, self); // 给 "datasource.nodeid" 赋值; rf.inject(source, self); // 给其可能包含@Resource的字段赋值;
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e); logger.log(Level.SEVERE, "DataSource inject error", e);
} }
}, DataSource.class); }, DataSource.class);
//------------------------------------- 注册CacheSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> { resourceFactory.register((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) && Sncp.isRemote((Service) src)) return; //远程模式不注入 CacheSource if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient((Service) src); SncpClient client = Sncp.getSncpClient(srcService);
Transport sameGroupTransport = Sncp.getSameGroupTransport((Service) src); Transport sameGroupTransport = Sncp.getSameGroupTransport(srcService);
Transport[] dts = Sncp.getDiffGroupTransports((Service) src); Transport[] dts = Sncp.getDiffGroupTransports((Service) src);
List<Transport> diffGroupTransports = dts == null ? new ArrayList<>() : Arrays.asList(dts); List<Transport> diffGroupTransports = dts == null ? new ArrayList<>() : Arrays.asList(dts);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheSourceService.class, sncpAddr, sameGroupTransport, diffGroupTransports); final CacheMemorySource source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheMemorySource.class, sncpAddr, Sncp.getSncpGroup(srcService), Sncp.getGroups(srcService), Sncp.getConf(srcService), sameGroupTransport, diffGroupTransports);
Type genericType = field.getGenericType(); Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null; ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1]; Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
@@ -243,12 +273,11 @@ public abstract class NodeServer {
rf.inject(source, self); // rf.inject(source, self); //
((Service) source).init(null); ((Service) source).init(null);
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheSourceService if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr); NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports); Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, sncpServer.getSncpGroup(), gs, null); sncpServer.getSncpServer().addSncpServlet((Service) source);
sncpServer.getSncpServer().addSncpServlet(wrapper); logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
} }
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source); logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
} catch (Exception e) { } catch (Exception e) {
@@ -265,55 +294,55 @@ public abstract class NodeServer {
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory; ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
for (FilterEntry<Service> entry : entrys) { //service实现类 for (FilterEntry<Service> entry : entrys) { //service实现类
final Class<? extends Service> type = entry.getType(); final Class<? extends Service> serviceImplClass = entry.getType();
if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过 if (Modifier.isFinal(serviceImplClass.getModifiers())) continue; //修饰final的类跳过
if (!Modifier.isPublic(type.getModifiers())) continue; if (!Modifier.isPublic(serviceImplClass.getModifiers())) continue;
if (entry.isExpect()) { if (entry.isExpect()) {
if (Modifier.isAbstract(type.getModifiers())) continue; //修饰abstract的类跳过 if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
if (DataSource.class.isAssignableFrom(type)) continue; if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
if (CacheSource.class.isAssignableFrom(type)) continue; if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
if (DataCacheListener.class.isAssignableFrom(type)) continue; if (DataCacheListener.class.isAssignableFrom(serviceImplClass)) continue;
if (WebSocketNode.class.isAssignableFrom(type)) continue; if (WebSocketNode.class.isAssignableFrom(serviceImplClass)) continue;
} }
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty()); if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
if (resourceFactory.find(entry.getName(), type) != null) { //Server加载Service时需要判断是否已经加载过了。 Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
Service oldother = resourceFactory.find(entry.getName(), type); if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother)); interceptorServices.add(oldother);
continue; continue;
} }
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。 final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup); if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup);
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) //非SNCP的Server通常是单点服务 final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !serviceImplClass.isInterface() && !Modifier.isAbstract(serviceImplClass.getModifiers())) //非SNCP的Server通常是单点服务
|| groups.contains(this.sncpGroup) //本地IP含在内的 || groups.contains(this.sncpGroup) //本地IP含在内的
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置 || (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|| type.getAnnotation(LocalService.class) != null;//本地模式 || serviceImplClass.getAnnotation(LocalService.class) != null;//本地模式
if (localed && (type.isInterface() || Modifier.isAbstract(type.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类 if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final BiConsumer<ResourceFactory, Boolean> runner = (ResourceFactory rf, Boolean needinject) -> { final BiConsumer<ResourceFactory, Boolean> runner = (ResourceFactory rf, Boolean needinject) -> {
try { try {
Service service; Service service;
if (localed) { //本地模式 if (localed) { //本地模式
service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type, service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), serviceImplClass,
NodeServer.this.sncpAddress, loadTransport(NodeServer.this.sncpGroup), loadTransports(groups)); NodeServer.this.sncpAddress, NodeServer.this.sncpGroup, groups, entry.getProperty(), loadTransport(NodeServer.this.sncpGroup), loadTransports(groups));
} else { } else {
service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, NodeServer.this.sncpAddress, loadTransport(groups)); service = Sncp.createRemoteService(entry.getName(), getExecutor(), serviceImplClass, NodeServer.this.sncpAddress, null, groups, entry.getProperty(), loadTransport(groups));
} }
if (SncpClient.parseMethod(type).isEmpty()) return; //class没有可用的方法 通常为BaseService if (SncpClient.parseMethod(serviceImplClass).isEmpty()) return; //class没有可用的方法 通常为BaseService
final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty()); //final ServiceWrapper wrapper = new ServiceWrapper(serviceImplClass, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty());
for (final Class restype : wrapper.getTypes()) { for (final Class restype : Sncp.getResourceTypes(service)) {
if (resourceFactory.find(wrapper.getName(), restype) == null) { if (resourceFactory.find(entry.getName(), restype) == null) {
regFactory.register(wrapper.getName(), restype, wrapper.getService()); regFactory.register(entry.getName(), restype, service);
if (needinject) rf.inject(wrapper.getService()); //动态加载的Service也存在按需加载的注入资源 if (needinject) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
} else if (isSNCP() && !entry.isAutoload()) { } else if (isSNCP() && !entry.isAutoload()) {
throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat."); throw new RuntimeException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat.");
} }
} }
if (wrapper.isRemote()) { if (Sncp.isRemote(service)) {
remoteServiceWrappers.add(wrapper); remoteServices.add(service);
} else { } else {
localServiceWrappers.add(wrapper); localServices.add(service);
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, service)); interceptorServices.add(service);
if (consumer != null) consumer.accept(wrapper); if (consumer != null) consumer.accept(service);
} }
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw ex; throw ex;
@@ -325,7 +354,9 @@ public abstract class NodeServer {
ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> { ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
runner.accept(rf, true); runner.accept(rf, true);
}; };
for (final Class restype : ServiceWrapper.parseTypes(entry.getType())) { ResourceType rty = entry.getType().getAnnotation(ResourceType.class);
Class[] resTypes = rty == null ? new Class[]{} : rty.value();
for (final Class restype : resTypes) {
resourceFactory.register(resourceLoader, restype); resourceFactory.register(resourceLoader, restype);
} }
} else { } else {
@@ -339,30 +370,38 @@ public abstract class NodeServer {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
//---------------- inject ---------------- //---------------- inject ----------------
new ArrayList<>(localServiceWrappers).forEach(y -> { new ArrayList<>(localServices).forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this); resourceFactory.inject(y, NodeServer.this);
calcMaxLength(y);
}); });
new ArrayList<>(remoteServiceWrappers).forEach(y -> { new ArrayList<>(remoteServices).forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this); resourceFactory.inject(y, NodeServer.this);
calcMaxLength(y);
}); });
if (sb != null) { if (sb != null) {
remoteServiceWrappers.forEach(y -> { remoteServices.forEach(y -> {
sb.append(threadName).append(y.toSimpleString()).append(" loaded and injected").append(LINE_SEPARATOR); sb.append(threadName).append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" load and inject").append(LINE_SEPARATOR);
}); });
} }
//----------------- init ----------------- //----------------- init -----------------
List<ServiceWrapper> swlist = new ArrayList<>(localServiceWrappers); List<Service> swlist = new ArrayList<>(localServices);
Collections.sort(swlist); Collections.sort(swlist, (o1, o2) -> {
localServiceWrappers.clear(); int rs = Sncp.getResourceTypes(o1)[0].getName().compareTo(Sncp.getResourceTypes(o2)[0].getName());
localServiceWrappers.addAll(swlist); if (rs == 0) rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2));
return rs;
});
localServices.clear();
localServices.addAll(swlist);
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>(); final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
CountDownLatch clds = new CountDownLatch(localServiceWrappers.size()); CountDownLatch clds = new CountDownLatch(localServices.size());
localServiceWrappers.parallelStream().forEach(y -> { localServices.parallelStream().forEach(y -> {
try { try {
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
y.getService().init(y.getConf()); y.init(Sncp.getConf(y));
long e = System.currentTimeMillis() - s; long e = System.currentTimeMillis() - s;
if (slist != null) slist.add(new StringBuilder().append(threadName).append(y.toSimpleString()).append(" loaded and inited ").append(e).append(" ms").append(LINE_SEPARATOR).toString()); 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());
} finally { } finally {
clds.countDown(); clds.countDown();
} }
@@ -378,6 +417,20 @@ public abstract class NodeServer {
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
} }
private void calcMaxLength(Service y) { //计算toString中的长度
maxNameLength = Math.max(maxNameLength, Sncp.getResourceName(y).length());
StringBuilder s = new StringBuilder();
Class[] types = Sncp.getResourceTypes(y);
if (types.length == 1) {
s.append(types[0].getName());
} else {
s.append('[');
s.append(Arrays.asList(types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
}
maxClassNameLength = Math.max(maxClassNameLength, s.length() + 1);
}
protected List<Transport> loadTransports(final HashSet<String> groups) { protected List<Transport> loadTransports(final HashSet<String> groups) {
if (groups == null) return null; if (groups == null) return null;
final List<Transport> transports = new ArrayList<>(); final List<Transport> transports = new ArrayList<>();
@@ -403,7 +456,7 @@ public abstract class NodeServer {
Transport first = transports.get(0); Transport first = transports.get(0);
GroupInfo ginfo = application.findGroupInfo(first.getName()); GroupInfo ginfo = application.findGroupInfo(first.getName());
Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(), Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs); ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
synchronized (application.resourceFactory) { synchronized (application.resourceFactory) {
transport = application.resourceFactory.find(groupid, Transport.class); transport = application.resourceFactory.find(groupid, Transport.class);
if (transport == null) { if (transport == null) {
@@ -429,7 +482,7 @@ public abstract class NodeServer {
Set<InetSocketAddress> addrs = ginfo.copyAddrs(); Set<InetSocketAddress> addrs = ginfo.copyAddrs();
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> "); if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(), transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs); ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
application.resourceFactory.register(group, transport); application.resourceFactory.register(group, transport);
} }
return transport; return transport;
@@ -532,12 +585,12 @@ public abstract class NodeServer {
public void shutdown() throws IOException { public void shutdown() throws IOException {
if (interceptor != null) interceptor.preShutdown(this); if (interceptor != null) interceptor.preShutdown(this);
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
localServiceWrappers.forEach(y -> { localServices.forEach(y -> {
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
y.getService().destroy(y.getConf()); y.destroy(Sncp.getConf(y));
long e = System.currentTimeMillis() - s; long e = System.currentTimeMillis() - s;
if (e > 2 && sb != null) { if (e > 2 && sb != null) {
sb.append(y.toSimpleString()).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR); sb.append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" destroy ").append(e).append("ms").append(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());
@@ -548,16 +601,16 @@ public abstract class NodeServer {
return (T) server; return (T) server;
} }
public Set<NodeInterceptor.InterceptorServiceWrapper> getInterceptorServiceWrappers() { public Set<Service> getInterceptorServices() {
return new LinkedHashSet<>(interceptorServiceWrappers); return new LinkedHashSet<>(interceptorServices);
} }
public Set<ServiceWrapper> getLocalServiceWrappers() { public Set<Service> getLocalServices() {
return new LinkedHashSet<>(localServiceWrappers); return new LinkedHashSet<>(localServices);
} }
public Set<ServiceWrapper> getRemoteServiceWrappers() { public Set<Service> getRemoteServices() {
return new LinkedHashSet<>(remoteServiceWrappers); return new LinkedHashSet<>(remoteServices);
} }
} }

View File

@@ -10,9 +10,11 @@ import java.util.*;
import java.util.logging.*; import java.util.logging.*;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.net.sncp.*; import org.redkale.net.sncp.*;
import org.redkale.service.Service;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* SNCP Server节点的配置Server
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -47,8 +49,8 @@ public class NodeSncpServer extends NodeServer {
return sncpServer == null ? null : sncpServer.getSocketAddress(); return sncpServer == null ? null : sncpServer.getSocketAddress();
} }
public void consumerAccept(ServiceWrapper wrapper) { public void consumerAccept(Service service) {
if (this.consumer != null) this.consumer.accept(wrapper); if (this.consumer != null) this.consumer.accept(service);
} }
@Override @Override
@@ -61,7 +63,7 @@ public class NodeSncpServer extends NodeServer {
List<SncpServlet> servlets = sncpServer.getSncpServlets(); List<SncpServlet> servlets = sncpServer.getSncpServlets();
Collections.sort(servlets); Collections.sort(servlets);
for (SncpServlet en : servlets) { for (SncpServlet en : servlets) {
if (sb != null) sb.append(threadName).append(" Loaded ").append(en).append(LINE_SEPARATOR); if (sb != null) sb.append(threadName).append(" Load ").append(en).append(LINE_SEPARATOR);
} }
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString()); if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
} }

View File

@@ -1,12 +1,12 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="UTF-8"><title>Document</title> <meta charset="UTF-8"><title>接口文档(apidoc生成)</title>
<style type="text/css"> <style type="text/css">
body {text-align: center;margin:auto;} body {text-align: center;margin:auto;}
a{text-decoration: none;} a{text-decoration: none;}
.table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;} .table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;}
.table td,.table th{padding: 0.4rem 1.2rem 0.4rem 1.2rem;border: 1px solid #aaa;} .table td,.table th{padding: 0.2rem 0.8rem 0.2rem 0.8rem;border: 1px solid #aaa;}
.table td {text-align: left;} .table td {text-align: left;}
.s {font-size: 0.8rem; vertical-align: middle;} .s {font-size: 0.8rem; vertical-align: middle;}
.subtable {border-spacing: 0;border: 0;margin:0;} .subtable {border-spacing: 0;border: 0;margin:0;}
@@ -25,13 +25,19 @@
html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">'); html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">');
html.push('<br/><br/><table class="table" align="center">'); html.push('<br/><br/><table class="table" align="center">');
for (var i = 0; i < jsoncontent.servers.length; i++) { for (var i = 0; i < jsoncontent.servers.length; i++) {
for (var j = 0; j < jsoncontent.servers[i].servlets.length; j++) { var servlets = jsoncontent.servers[i].servlets;
var servlet = jsoncontent.servers[i].servlets[j]; if (servlets.length && (servlets[0].comment || "").indexOf("【") === 0) {
servlets.sort(function (a, b) {
return a.comment > b.comment ? -1 : (a.comment == b.comment ? 0 : 1);
});
}
for (var j = 0; j < servlets.length; j++) {
var servlet = servlets[j];
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>'); if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>');
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>'); html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>'); html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
for (var k = 0; k < servlet.actions.length; k++) { for (var k = 0; k < servlet.mappings.length; k++) {
var action = servlet.actions[k]; var action = servlet.mappings[k];
html.push(' <tr>'); html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>'); html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>'); html.push('<td>' + action.comment + '</td>');
@@ -47,15 +53,22 @@
if (param.name == '&') { if (param.name == '&') {
paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>'); paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>');
} else { } else {
var c = ' style="font-weight:bold;"'; var w = param.required ? "font-weight:bold;" : "";
if (param.src == "HEADER") c = ' style="color:red;font-weight:bold;"'; var c = ' style="' + w + '"';
if (param.src == "COOKIE") c = ' style="color:blue;font-weight:bold;"'; if (param.src == "HEADER") c = ' style="color:red;' + w + '"';
if (param.src == "COOKIE") c = ' style="color:blue;' + w + '"';
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>'); paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
} }
} }
paramshtml.push('</table>'); paramshtml.push('</table>');
html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>'); html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>');
html.push('<td>' + action.result.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</td>'); var rs = [];
rs.push(action.result.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""));
var results = action.results || [];
for (var r = 0; r < results.length; r++) {
rs.push('<a href="#' + results[r].replace('[]', '') + '">' + results[r].replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</a>');
}
html.push('<td>' + rs.join("<br/>") + '</td>');
html.push('</tr>'); html.push('</tr>');
} }
} }
@@ -66,8 +79,20 @@
html.push(' <tr><td colspan="5"><table class="typetable">'); html.push(' <tr><td colspan="5"><table class="typetable">');
for (var fieldname in classmap[type]) { for (var fieldname in classmap[type]) {
var field = classmap[type][fieldname]; var field = classmap[type][fieldname];
var t = field.type.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""); var t = field.type.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\$/g, ".").replace(/([a-zA-Z0-9_\$]+\.)+/g, "");
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + (field.comment || '') + '</td></tr>'); if (t == 'boolean' || t == 'short' || t == 'int' || t == 'long' || t == 'float' || t == 'double'
|| t == 'boolean[]' || t == 'short[]' || t == 'int[]' || t == 'long[]' || t == 'float[]' || t == 'double[]') {
t = '<font color=blue>' + t + '</font>';
} else if (t == 'String' || t == 'String[]' || t == 'LongRange' || t.indexOf('Map&lt;') === 0) {
t = '<font color=red>' + t + '</font>';
}
var c = (field.comment || '');
if (field.primary) {
c = '【主键】 ' + c;
} else if (!field.updatable) {
c = '【只读】 ' + c;
}
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + c + '</td></tr>');
} }
html.push(' </table></td></tr>'); html.push(' </table></td></tr>');
} }
@@ -78,7 +103,7 @@
</script> </script>
<script> <script>
var jsoncontent = ${content}; var jsoncontent = '${content}'; //这里必须要用单引号引起来
document.write(createhtml(jsoncontent)); document.write(createhtml(jsoncontent));
</script> </script>
</body> </body>

View File

@@ -9,9 +9,9 @@ import java.lang.reflect.*;
import java.util.*; import java.util.*;
/** /**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组. * 数组的序列化操作类 <br>
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有采用int存储。 * 对象数组的反序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 * 支持一定程度的泛型。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -28,31 +28,53 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
private final Class componentClass; private final Class componentClass;
private final Decodeable<Reader, T> decoder; protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
private final Object lock = new Object();
public ArrayDecoder(final ConvertFactory factory, final Type type) { public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
if (type instanceof GenericArrayType) { try {
Type t = ((GenericArrayType) type).getGenericComponentType(); if (type instanceof GenericArrayType) {
this.componentType = t instanceof TypeVariable ? Object.class : t; Type t = ((GenericArrayType) type).getGenericComponentType();
} else if ((type instanceof Class) && ((Class) type).isArray()) { this.componentType = t instanceof TypeVariable ? Object.class : t;
this.componentType = ((Class) type).getComponentType(); } else if ((type instanceof Class) && ((Class) type).isArray()) {
} else { this.componentType = ((Class) type).getComponentType();
throw new ConvertException("(" + type + ") is not a array type"); } else {
throw new ConvertException("(" + type + ") is not a array type");
}
if (this.componentType instanceof ParameterizedType) {
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
} else {
this.componentClass = (Class) this.componentType;
}
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
} }
if (this.componentType instanceof ParameterizedType) {
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
} else {
this.componentClass = (Class) this.componentType;
}
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} }
@Override @Override
public T[] convertFrom(Reader in) { public T[] convertFrom(Reader in) {
final int len = in.readArrayB(); final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null; if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder; final Decodeable<Reader, T> localdecoder = this.decoder;
final List<T> result = new ArrayList(); final List<T> result = new ArrayList();
if (len == Reader.SIGN_NOLENGTH) { if (len == Reader.SIGN_NOLENGTH) {

View File

@@ -8,9 +8,9 @@ package org.redkale.convert;
import java.lang.reflect.*; import java.lang.reflect.*;
/** /**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组. * 数组的序列化操作类 <br>
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有必要采用int存储。 * 对象数组的序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 * 支持一定程度的泛型。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -29,19 +29,30 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
private final Encodeable<Writer, Object> encoder; private final Encodeable<Writer, Object> encoder;
private boolean inited = false;
private final Object lock = new Object();
public ArrayEncoder(final ConvertFactory factory, final Type type) { public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
if (type instanceof GenericArrayType) { try {
Type t = ((GenericArrayType) type).getGenericComponentType(); if (type instanceof GenericArrayType) {
this.componentType = t instanceof TypeVariable ? Object.class : t; Type t = ((GenericArrayType) type).getGenericComponentType();
} else if ((type instanceof Class) && ((Class) type).isArray()) { this.componentType = t instanceof TypeVariable ? Object.class : t;
this.componentType = ((Class) type).getComponentType(); } else if ((type instanceof Class) && ((Class) type).isArray()) {
} else { this.componentType = ((Class) type).getComponentType();
throw new ConvertException("(" + type + ") is not a array type"); } else {
throw new ConvertException("(" + type + ") is not a array type");
}
factory.register(type, this);
this.encoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder();
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
} }
factory.register(type, this);
this.encoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder();
} }
@Override @Override
@@ -55,6 +66,17 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
out.writeArrayE(); out.writeArrayE();
return; return;
} }
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeArrayB(value.length); out.writeArrayB(value.length);
final Type comp = this.componentType; final Type comp = this.componentType;
boolean first = true; boolean first = true;

View File

@@ -11,9 +11,8 @@ import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
/** /**
* 对象集合的反序列化. * Collection的反序列化操作类 <br>
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。 * 支持一定程度的泛型。 <br>
* 支持一定程度的泛型。
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -30,18 +29,29 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
protected Creator<Collection<T>> creator; protected Creator<Collection<T>> creator;
private final Decodeable<Reader, T> decoder; protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
private final Object lock = new Object();
public CollectionDecoder(final ConvertFactory factory, final Type type) { public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
if (type instanceof ParameterizedType) { try {
final ParameterizedType pt = (ParameterizedType) type; if (type instanceof ParameterizedType) {
this.componentType = pt.getActualTypeArguments()[0]; final ParameterizedType pt = (ParameterizedType) type;
this.creator = factory.loadCreator((Class) pt.getRawType()); this.componentType = pt.getActualTypeArguments()[0];
factory.register(type, this); this.creator = factory.loadCreator((Class) pt.getRawType());
this.decoder = factory.loadDecoder(this.componentType); factory.register(type, this);
} else { this.decoder = factory.loadDecoder(this.componentType);
throw new ConvertException("collectiondecoder not support the type (" + type + ")"); } else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
} }
} }
@@ -49,6 +59,17 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
public Collection<T> convertFrom(Reader in) { public Collection<T> convertFrom(Reader in) {
final int len = in.readArrayB(); final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null; if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder; final Decodeable<Reader, T> localdecoder = this.decoder;
final Collection<T> result = this.creator.create(); final Collection<T> result = this.creator.create();
if (len == Reader.SIGN_NOLENGTH) { if (len == Reader.SIGN_NOLENGTH) {

View File

@@ -9,11 +9,12 @@ import java.lang.reflect.*;
import java.util.Collection; import java.util.Collection;
/** /**
* 对象集合的序列化. * Collection的序列化操作类 <br>
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。 * 支持一定程度的泛型。 <br>
* 支持一定程度的泛型。 *
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
* @param <T> 序列化的集合元素类型 * @param <T> 序列化的集合元素类型
*/ */
@@ -24,17 +25,28 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
private final Encodeable<Writer, Object> encoder; private final Encodeable<Writer, Object> encoder;
private boolean inited = false;
private final Object lock = new Object();
public CollectionEncoder(final ConvertFactory factory, final Type type) { public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
if (type instanceof ParameterizedType) { try {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; if (type instanceof ParameterizedType) {
if (t instanceof TypeVariable) { Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
this.encoder = factory.getAnyEncoder(); if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
} else {
this.encoder = factory.loadEncoder(t);
}
} else { } else {
this.encoder = factory.loadEncoder(t); this.encoder = factory.getAnyEncoder();
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
} }
} else {
this.encoder = factory.getAnyEncoder();
} }
} }
@@ -49,6 +61,17 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
out.writeArrayE(); out.writeArrayE();
return; return;
} }
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeArrayB(value.size()); out.writeArrayB(value.size());
boolean first = true; boolean first = true;
for (Object v : value) { for (Object v : value) {

View File

@@ -6,7 +6,7 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 序列化操作类 * 序列化/反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -10,11 +10,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* 用于类名的别名 类似javax.persistence.Table * 用于类名的别名, 该值必须是全局唯一 <br>
* 该值必须是全局唯一 * 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。 *
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
@Inherited @Inherited
@@ -23,5 +24,10 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ConvertEntity { public @interface ConvertEntity {
/**
* 别名值
*
* @return String
*/
String value(); String value();
} }

View File

@@ -5,8 +5,11 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 序列化自定义异常类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class ConvertException extends RuntimeException { public class ConvertException extends RuntimeException {

View File

@@ -17,6 +17,7 @@ import org.redkale.convert.ext.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 序列化模块的工厂类用于注册自定义的序列化类型获取Convert
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -91,6 +92,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance); this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance);
this.register(Pattern.class, PatternSimpledCoder.instance); this.register(Pattern.class, PatternSimpledCoder.instance);
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance); this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
this.register(AsyncHandler.class, AsyncHandlerSimpledCoder.instance);
this.register(URL.class, URLSimpledCoder.instance); this.register(URL.class, URLSimpledCoder.instance);
this.register(URI.class, URISimpledCoder.instance); this.register(URI.class, URISimpledCoder.instance);
//--------------------------------------------------------- //---------------------------------------------------------
@@ -104,6 +106,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(double[].class, DoubleArraySimpledCoder.instance); this.register(double[].class, DoubleArraySimpledCoder.instance);
this.register(String[].class, StringArraySimpledCoder.instance); this.register(String[].class, StringArraySimpledCoder.instance);
//--------------------------------------------------------- //---------------------------------------------------------
this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class));
this.register(HttpCookie.class, new Creator<HttpCookie>() { this.register(HttpCookie.class, new Creator<HttpCookie>() {
@Override @Override
@Creator.ConstructorParameters({"name", "value"}) @Creator.ConstructorParameters({"name", "value"})

View File

@@ -6,8 +6,11 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 序列化类型枚举,结合&#64;ConvertColumn使用
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public enum ConvertType { public enum ConvertType {

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 字段的反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -88,6 +89,6 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
@Override @Override
public String toString() { public String toString() {
return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + decoder + '}'; return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + (decoder == null ? null : decoder.getClass().getName()) + '}';
} }
} }

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* 反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 字段的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -81,6 +82,6 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
@Override @Override
public String toString() { public String toString() {
return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + encoder + '}'; return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + (encoder == null ? null : encoder.getClass().getName()) + '}';
} }
} }

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* 序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -11,8 +11,11 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* Map的反序列化操作类 <br>
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
* @param <K> Map key的数据类型 * @param <K> Map key的数据类型
* @param <V> Map value的数据类型 * @param <V> Map value的数据类型
@@ -28,27 +31,49 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
protected Creator<Map<K, V>> creator; protected Creator<Map<K, V>> creator;
private final Decodeable<Reader, K> keyDecoder; protected final Decodeable<Reader, K> keyDecoder;
private final Decodeable<Reader, V> valueDecoder; protected final Decodeable<Reader, V> valueDecoder;
private boolean inited = false;
private final Object lock = new Object();
public MapDecoder(final ConvertFactory factory, final Type type) { public MapDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
if (type instanceof ParameterizedType) { try {
final ParameterizedType pt = (ParameterizedType) type; if (type instanceof ParameterizedType) {
this.keyType = pt.getActualTypeArguments()[0]; final ParameterizedType pt = (ParameterizedType) type;
this.valueType = pt.getActualTypeArguments()[1]; this.keyType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType()); this.valueType = pt.getActualTypeArguments()[1];
factory.register(type, this); this.creator = factory.loadCreator((Class) pt.getRawType());
this.keyDecoder = factory.loadDecoder(this.keyType); factory.register(type, this);
this.valueDecoder = factory.loadDecoder(this.valueType); this.keyDecoder = factory.loadDecoder(this.keyType);
} else { this.valueDecoder = factory.loadDecoder(this.valueType);
throw new ConvertException("mapdecoder not support the type (" + type + ")"); } else {
throw new ConvertException("mapdecoder not support the type (" + type + ")");
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
} }
} }
@Override @Override
public Map<K, V> convertFrom(Reader in) { public Map<K, V> convertFrom(Reader in) {
if (this.keyDecoder == null || this.valueDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final int len = in.readMapB(); final int len = in.readMapB();
if (len == Reader.SIGN_NULL) return null; if (len == Reader.SIGN_NULL) return null;
final Map<K, V> result = this.creator.create(); final Map<K, V> result = this.creator.create();

View File

@@ -10,6 +10,7 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* Map的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -27,15 +28,26 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
private final Encodeable<Writer, V> valencoder; private final Encodeable<Writer, V> valencoder;
private boolean inited = false;
private final Object lock = new Object();
public MapEncoder(final ConvertFactory factory, final Type type) { public MapEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
if (type instanceof ParameterizedType) { try {
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments(); if (type instanceof ParameterizedType) {
this.keyencoder = factory.loadEncoder(pt[0]); final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
this.valencoder = factory.loadEncoder(pt[1]); this.keyencoder = factory.loadEncoder(pt[0]);
} else { this.valencoder = factory.loadEncoder(pt[1]);
this.keyencoder = factory.getAnyEncoder(); } else {
this.valencoder = factory.getAnyEncoder(); this.keyencoder = factory.getAnyEncoder();
this.valencoder = factory.getAnyEncoder();
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
} }
} }
@@ -46,6 +58,18 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
out.writeNull(); out.writeNull();
return; return;
} }
if (this.keyencoder == null || this.valencoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeMapB(values.size()); out.writeMapB(values.size());
boolean first = true; boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) { for (Map.Entry<K, V> en : values.entrySet()) {

View File

@@ -13,6 +13,7 @@ import java.util.Set;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 自定义对象的反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -66,6 +67,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
clazz = (Class) type; clazz = (Class) type;
} }
this.creator = factory.loadCreator(clazz); this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
final Set<DeMember> list = new HashSet(); final Set<DeMember> list = new HashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator); final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
@@ -75,7 +77,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (Modifier.isStatic(field.getModifiers())) continue; if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field); ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(field.getGenericType(), this.type); Type t = TypeToken.createClassType(field.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t))); list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t)));
} }
final boolean reversible = factory.isReversible(); final boolean reversible = factory.isReversible();
@@ -85,6 +87,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (method.isSynthetic()) continue; if (method.isSynthetic()) continue;
if (method.getName().length() < 4) continue; if (method.getName().length() < 4) continue;
if (!method.getName().startsWith("set")) continue; if (!method.getName().startsWith("set")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (method.getParameterTypes().length != 1) continue; if (method.getParameterTypes().length != 1) continue;
if (method.getReturnType() != void.class) continue; if (method.getReturnType() != void.class) continue;
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) { if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
@@ -97,7 +100,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
} }
ref = factory.findRef(method); ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(method.getGenericParameterTypes()[0], this.type); Type t = TypeToken.createClassType(method.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t))); list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t)));
} }
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法 if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
@@ -113,7 +116,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
//不存在setter方法 //不存在setter方法
try { try {
Field f = clazz.getDeclaredField(constructorField); Field f = clazz.getDeclaredField(constructorField);
Type t = ObjectEncoder.createClassType(f.getGenericType(), this.type); Type t = TypeToken.createClassType(f.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t))); list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t)));
} catch (NoSuchFieldException nsfe) { //不存在field 可能存在getter方法 } catch (NoSuchFieldException nsfe) { //不存在field 可能存在getter方法
char[] fs = constructorField.toCharArray(); char[] fs = constructorField.toCharArray();
@@ -125,7 +128,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
} catch (NoSuchMethodException ex) { } catch (NoSuchMethodException ex) {
getter = clazz.getMethod("is" + mn); getter = clazz.getMethod("is" + mn);
} }
Type t = ObjectEncoder.createClassType(getter.getGenericParameterTypes()[0], this.type); Type t = TypeToken.createClassType(getter.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t))); list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
} }
} }

View File

@@ -10,6 +10,7 @@ import java.util.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 自定义对象的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -67,7 +68,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (Modifier.isStatic(field.getModifiers())) continue; if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field); ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = createClassType(field.getGenericType(), this.type); Type t = TypeToken.createClassType(field.getGenericType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t))); list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t)));
} }
for (final Method method : clazz.getMethods()) { for (final Method method : clazz.getMethods()) {
@@ -77,6 +78,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (method.getName().length() < 3) continue; if (method.getName().length() < 3) continue;
if (method.getName().equals("getClass")) continue; if (method.getName().equals("getClass")) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (method.getParameterTypes().length != 0) continue; if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() == void.class) continue; if (method.getReturnType() == void.class) continue;
if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) { if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
@@ -89,7 +91,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
} }
ref = factory.findRef(method); ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
Type t = createClassType(method.getGenericReturnType(), this.type); Type t = TypeToken.createClassType(method.getGenericReturnType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t))); list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t)));
} }
this.members = list.toArray(new EnMember[list.size()]); this.members = list.toArray(new EnMember[list.size()]);
@@ -144,42 +146,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
} }
static Type createClassType(final Type type, final Type declaringType0) {
if (TypeToken.isClassType(type)) return type;
if (type instanceof ParameterizedType) { // e.g. Map<String, String>
final ParameterizedType pt = (ParameterizedType) type;
final Type[] paramTypes = pt.getActualTypeArguments();
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = createClassType(paramTypes[i], declaringType0);
}
return TypeToken.createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes);
}
Type declaringType = declaringType0;
if (declaringType instanceof Class) {
do {
declaringType = ((Class) declaringType).getGenericSuperclass();
if (declaringType == Object.class) return Object.class;
} while (declaringType instanceof Class);
}
//存在通配符则declaringType 必须是 ParameterizedType
if (!(declaringType instanceof ParameterizedType)) return Object.class;
final ParameterizedType declaringPType = (ParameterizedType) declaringType;
final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters();
final Type[] desTypes = declaringPType.getActualTypeArguments();
if (type instanceof WildcardType) { // e.g. <? extends Serializable>
final WildcardType wt = (WildcardType) type;
for (Type f : wt.getUpperBounds()) {
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
return type;
}
// //
// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) { // static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
// if (type instanceof Class) { //e.g. String // if (type instanceof Class) { //e.g. String
@@ -228,7 +194,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
// } // }
// return type; // return type;
// } // }
static boolean contains(String[] values, String value) { static boolean contains(String[] values, String value) {
for (String str : values) { for (String str : values) {
if (str.equals(value)) return true; if (str.equals(value)) return true;

View File

@@ -6,6 +6,7 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* 反序列化的数据读取流
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -42,6 +43,7 @@ public abstract class Reader {
* 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。 * 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。
* *
* @param clazz 类名 * @param clazz 类名
*
* @return 返回字段数 * @return 返回字段数
*/ */
public String readObjectB(final Class clazz) { public String readObjectB(final Class clazz) {
@@ -86,6 +88,7 @@ public abstract class Reader {
* 根据字段读取字段对应的DeMember * 根据字段读取字段对应的DeMember
* *
* @param members DeMember的全量集合 * @param members DeMember的全量集合
*
* @return 匹配的DeMember * @return 匹配的DeMember
*/ */
public abstract DeMember readFieldName(final DeMember[] members); public abstract DeMember readFieldName(final DeMember[] members);

View File

@@ -9,6 +9,8 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* 简易类的序列化和反序列化操作类 <br>
* 能序列化为Boolean、Number或者字符串的类视为简易类 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 序列化的数据输出流
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -11,6 +11,7 @@ import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 以ByteBuffer为数据载体的BsonReader
* *
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -123,13 +124,13 @@ public class BsonByteBufferReader extends BsonReader {
} }
} }
return ((((long) readByte() & 0xff) << 56) return ((((long) readByte() & 0xff) << 56)
| (((long) readByte() & 0xff) << 48) | (((long) readByte() & 0xff) << 48)
| (((long) readByte() & 0xff) << 40) | (((long) readByte() & 0xff) << 40)
| (((long) readByte() & 0xff) << 32) | (((long) readByte() & 0xff) << 32)
| (((long) readByte() & 0xff) << 24) | (((long) readByte() & 0xff) << 24)
| (((long) readByte() & 0xff) << 16) | (((long) readByte() & 0xff) << 16)
| (((long) readByte() & 0xff) << 8) | (((long) readByte() & 0xff) << 8)
| (((long) readByte() & 0xff))); | (((long) readByte() & 0xff)));
} }
protected byte[] read(final int len) { protected byte[] read(final int len) {

View File

@@ -7,8 +7,10 @@ package org.redkale.convert.bson;
import java.nio.*; import java.nio.*;
import java.util.function.*; import java.util.function.*;
import org.redkale.util.Utility;
/** /**
* 以ByteBuffer为数据载体的BsonWriter
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -78,20 +80,14 @@ public class BsonByteBufferWriter extends BsonWriter {
if (!buffer.hasRemaining()) { if (!buffer.hasRemaining()) {
buffer.flip(); buffer.flip();
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
this.index++; this.index++;
} }
int len = buffer.remaining(); int len = buffer.remaining();
int size = 0; int size = 0;
while (len < byteLength) { while (len < byteLength) {
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
len += buffer.remaining(); len += buffer.remaining();
size++; size++;
} }

View File

@@ -15,21 +15,21 @@ import org.redkale.util.*;
/** /**
* <blockquote><pre> * <blockquote><pre>
* BSON协议格式: * BSON协议格式:
* 1). 基本数据类型: 直接转换成byte[] * 1) 基本数据类型: 直接转换成byte[]
* 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 * 2) SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
* 3). String: length(4 bytes) + byte[](utf8); * 3) String: length(4 bytes) + byte[](utf8);
* 4). 数组: length(4 bytes) + byte[]... * 4) 数组: length(4 bytes) + byte[]...
* 5). Object: * 5) Object:
* 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名) * 1 realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
* 2. 空字符串(SmallString) * 2 空字符串(SmallString)
* 3. SIGN_OBJECTB 标记位值固定为0xBB (short) * 3 SIGN_OBJECTB 标记位值固定为0xBB (short)
* 4. 循环字段值: * 4 循环字段值:
* 4.1 SIGN_HASNEXT 标记位值固定为1 (byte) * 4.1 SIGN_HASNEXT 标记位值固定为1 (byte)
* 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object * 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object
* 4.3 字段名 (SmallString) * 4.3 字段名 (SmallString)
* 4.4 字段的值Object * 4.4 字段的值Object
* 5. SIGN_NONEXT 标记位值固定为0 (byte) * 5 SIGN_NONEXT 标记位值固定为0 (byte)
* 6. SIGN_OBJECTE 标记位值固定为0xEE (short) * 6 SIGN_OBJECTE 标记位值固定为0xEE (short)
* *
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>

View File

@@ -7,8 +7,10 @@ package org.redkale.convert.bson;
import java.io.Serializable; import java.io.Serializable;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.util.AnyValue;
/** /**
* BSON的ConvertFactory
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -27,6 +29,9 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
static { static {
instance.register(Serializable.class, objectDecoder); instance.register(Serializable.class, objectDecoder);
instance.register(Serializable.class, objectEncoder); instance.register(Serializable.class, objectEncoder);
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
} }
private BsonFactory(BsonFactory parent, boolean tiny) { private BsonFactory(BsonFactory parent, boolean tiny) {

View File

@@ -5,13 +5,13 @@
*/ */
package org.redkale.convert.bson; package org.redkale.convert.bson;
import java.util.function.*;
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.*; import org.redkale.convert.ext.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* BSON数据源
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -42,19 +42,7 @@ public class BsonReader extends Reader {
} }
public static ObjectPool<BsonReader> createPool(int max) { public static ObjectPool<BsonReader> createPool(int max) {
return new ObjectPool<BsonReader>(max, new Creator<BsonReader>() { return new ObjectPool<>(max, (Object... params) -> new BsonReader(), null, (t) -> t.recycle());
@Override
public BsonReader create(Object... params) {
return new BsonReader();
}
}, null, new Predicate<BsonReader>() {
@Override
public boolean test(BsonReader t) {
return t.recycle();
}
});
} }
public BsonReader(byte[] bytes) { public BsonReader(byte[] bytes) {
@@ -164,7 +152,7 @@ public class BsonReader extends Reader {
if (bt == Reader.SIGN_NULL) return null; if (bt == Reader.SIGN_NULL) return null;
if (bt != SIGN_OBJECTB) { if (bt != SIGN_OBJECTB) {
throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB) throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB)
+ " (position = " + position + ") but '" + currentByte() + "'"); + " (position = " + position + ") but '" + currentByte() + "'");
} }
return ""; return "";
} }
@@ -173,7 +161,7 @@ public class BsonReader extends Reader {
public final void readObjectE(final Class clazz) { public final void readObjectE(final Class clazz) {
if (readShort() != SIGN_OBJECTE) { if (readShort() != SIGN_OBJECTE) {
throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE) throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE)
+ " (position = " + position + ") but '" + currentByte() + "'"); + " (position = " + position + ") but '" + currentByte() + "'");
} }
} }
@@ -223,7 +211,7 @@ public class BsonReader extends Reader {
byte b = readByte(); byte b = readByte();
if (b == SIGN_HASNEXT) return true; if (b == SIGN_HASNEXT) return true;
if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT) if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT)
+ " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")"); + " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")");
return false; return false;
} }
@@ -272,19 +260,19 @@ public class BsonReader extends Reader {
@Override @Override
public int readInt() { public int readInt() {
return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16) return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16)
| ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
} }
@Override @Override
public long readLong() { public long readLong() {
return ((((long) content[++this.position] & 0xff) << 56) return ((((long) content[++this.position] & 0xff) << 56)
| (((long) content[++this.position] & 0xff) << 48) | (((long) content[++this.position] & 0xff) << 48)
| (((long) content[++this.position] & 0xff) << 40) | (((long) content[++this.position] & 0xff) << 40)
| (((long) content[++this.position] & 0xff) << 32) | (((long) content[++this.position] & 0xff) << 32)
| (((long) content[++this.position] & 0xff) << 24) | (((long) content[++this.position] & 0xff) << 24)
| (((long) content[++this.position] & 0xff) << 16) | (((long) content[++this.position] & 0xff) << 16)
| (((long) content[++this.position] & 0xff) << 8) | (((long) content[++this.position] & 0xff) << 8)
| (((long) content[++this.position] & 0xff))); | (((long) content[++this.position] & 0xff)));
} }
@Override @Override

View File

@@ -6,7 +6,6 @@
package org.redkale.convert.bson; package org.redkale.convert.bson;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.function.Predicate;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.util.*; import org.redkale.util.*;
@@ -28,19 +27,7 @@ public class BsonWriter extends Writer {
protected boolean tiny; protected boolean tiny;
public static ObjectPool<BsonWriter> createPool(int max) { public static ObjectPool<BsonWriter> createPool(int max) {
return new ObjectPool<BsonWriter>(max, new Creator<BsonWriter>() { return new ObjectPool<>(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());
@Override
public BsonWriter create(Object... params) {
return new BsonWriter();
}
}, null, new Predicate<BsonWriter>() {
@Override
public boolean test(BsonWriter t) {
return t.recycle();
}
});
} }
public byte[] toArray() { public byte[] toArray() {
@@ -82,6 +69,7 @@ public class BsonWriter extends Writer {
* 扩充指定长度的缓冲区 * 扩充指定长度的缓冲区
* *
* @param len 扩容长度 * @param len 扩容长度
*
* @return 固定0 * @return 固定0
*/ */
protected int expand(int len) { protected int expand(int len) {
@@ -248,11 +236,11 @@ public class BsonWriter extends Writer {
return; return;
} }
char[] chars = Utility.charArray(value); char[] chars = Utility.charArray(value);
if (chars.length > 255) throw new ConvertException("'" + value + "' has very long length"); if (chars.length > 255) throw new ConvertException("'" + value + "' have very long length");
byte[] bytes = new byte[chars.length + 1]; byte[] bytes = new byte[chars.length + 1];
bytes[0] = (byte) chars.length; bytes[0] = (byte) chars.length;
for (int i = 0; i < chars.length; i++) { for (int i = 0; i < chars.length; i++) {
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' has double-word"); if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' have double-word");
bytes[i + 1] = (byte) chars[i]; bytes[i + 1] = (byte) chars[i];
} }
writeTo(bytes); writeTo(bytes);

View File

@@ -0,0 +1,36 @@
/*
* 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.AsyncHandler;
/**
* AsyncHandlerSimpledCoder 的SimpledCoder实现, 只输出null
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class AsyncHandlerSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, AsyncHandler> {
public static final AsyncHandlerSimpledCoder instance = new AsyncHandlerSimpledCoder();
@Override
public void convertTo(W out, AsyncHandler value) {
out.writeObjectNull(AsyncHandler.class);
}
@Override
public AsyncHandler convertFrom(R in) {
in.readObjectB(AsyncHandler.class);
return null;
}
}

View File

@@ -38,7 +38,7 @@ public class TypeSimpledCoder<R extends Reader, W extends Writer> extends Simple
if (str == null) return null; if (str == null) return null;
try { try {
return Class.forName(str); return Class.forName(str);
} catch (Exception e) { } catch (Throwable e) {
return null; return null;
} }
} }

View File

@@ -11,6 +11,7 @@ import org.redkale.convert.*;
import static org.redkale.convert.Reader.*; import static org.redkale.convert.Reader.*;
/** /**
* 以ByteBuffer为数据载体的JsonReader <br>
* *
* 只支持UTF-8格式 * 只支持UTF-8格式
* *

View File

@@ -13,6 +13,7 @@ import org.redkale.convert.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 以ByteBuffer为数据载体的JsonWriter
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -84,20 +85,14 @@ public class JsonByteBufferWriter extends JsonWriter {
if (!buffer.hasRemaining()) { if (!buffer.hasRemaining()) {
buffer.flip(); buffer.flip();
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
this.index++; this.index++;
} }
int len = buffer.remaining(); int len = buffer.remaining();
int size = 0; int size = 0;
while (len < byteLength) { while (len < byteLength) {
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
len += buffer.remaining(); len += buffer.remaining();
size++; size++;
} }

View File

@@ -10,9 +10,10 @@ import java.math.BigInteger;
import java.net.*; import java.net.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.ext.*; import org.redkale.convert.ext.*;
import org.redkale.util.DLong; import org.redkale.util.*;
/** /**
* JSON的ConvertFactory
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -29,6 +30,9 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance); instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.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.loadEncoder(AnyValue.DefaultAnyValue.class));
} }
private JsonFactory(JsonFactory parent, boolean tiny) { private JsonFactory(JsonFactory parent, boolean tiny) {

View File

@@ -10,6 +10,7 @@ import static org.redkale.convert.Reader.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* JSON数据源
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -17,47 +17,65 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* 服务器上下文对象
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class Context { public class Context {
private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Charset UTF8 = Charset.forName("UTF-8");
//服务启动时间
protected final long serverStartTime; protected final long serverStartTime;
//Server的线程池
protected final ExecutorService executor; protected final ExecutorService executor;
//ByteBuffer的容量默认8K
protected final int bufferCapacity; protected final int bufferCapacity;
//ByteBuffer对象池
protected final ObjectPool<ByteBuffer> bufferPool; protected final ObjectPool<ByteBuffer> bufferPool;
//Response对象池
protected final ObjectPool<Response> responsePool; protected final ObjectPool<Response> responsePool;
//服务的根Servlet
protected final PrepareServlet prepare; protected final PrepareServlet prepare;
//服务的监听地址
private final InetSocketAddress address; private final InetSocketAddress address;
//字符集
protected final Charset charset; protected final Charset charset;
//请求内容的大小上限, 默认64K
protected final int maxbody; protected final int maxbody;
//IO读取的超时时间
protected final int readTimeoutSecond; protected final int readTimeoutSecond;
//IO写入的超时时间
protected final int writeTimeoutSecond; protected final int writeTimeoutSecond;
//日志Logger
protected final Logger logger; protected final Logger logger;
//BSON操作工厂
protected final BsonFactory bsonFactory; protected final BsonFactory bsonFactory;
//JSON操作工厂
protected final JsonFactory jsonFactory; protected final JsonFactory jsonFactory;
//监控对象
protected final WatchFactory watch; protected final WatchFactory watch;
public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool, public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,
final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final WatchFactory watch, final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final WatchFactory watch,
final int readTimeoutSecond, final int writeTimeoutSecond) { final int readTimeoutSecond, final int writeTimeoutSecond) {
this.serverStartTime = serverStartTime; this.serverStartTime = serverStartTime;
this.logger = logger; this.logger = logger;
this.executor = executor; this.executor = executor;
@@ -91,8 +109,12 @@ public class Context {
return charset; return charset;
} }
public void submit(Runnable r) { public Future<?> submitAsync(Runnable r) {
executor.submit(r); return executor.submit(r);
}
public void runAsync(Runnable r) {
executor.execute(r);
} }
public int getBufferCapacity() { public int getBufferCapacity() {

View File

@@ -11,8 +11,11 @@ import java.util.logging.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 根Servlet的处理逻辑类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -14,6 +14,9 @@ import java.util.logging.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 根Servlet 一个Server只能存在一个根Servlet
*
* 用于分发Request请求
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -31,9 +34,33 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
protected final AtomicLong illRequestCounter = new AtomicLong(); //错误请求次数 protected final AtomicLong illRequestCounter = new AtomicLong(); //错误请求次数
protected final Set<S> servlets = new HashSet<>(); private final Object lock1 = new Object();
protected final Map<K, S> mappings = new HashMap<>(); private Set<S> servlets = new HashSet<>();
private final Object lock2 = new Object();
private Map<K, S> mappings = new HashMap<>();
protected void putServlet(S servlet) {
synchronized (lock1) {
Set<S> newservlets = new HashSet<>(servlets);
newservlets.add(servlet);
this.servlets = newservlets;
}
}
protected void putMapping(K key, S value) {
synchronized (lock2) {
Map<K, S> newmappings = new HashMap<>(mappings);
newmappings.put(key, value);
this.mappings = newmappings;
}
}
protected S mappingServlet(K key) {
return mappings.get(key);
}
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings); public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);

View File

@@ -13,6 +13,7 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
* 协议底层Server
* *
* <p> 详情见: https://redkale.org * <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
@@ -91,7 +92,7 @@ public abstract class ProtocolServer {
SocketAddress address = serchannel.receive(buffer); SocketAddress address = serchannel.receive(buffer);
buffer.flip(); buffer.flip();
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond); AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
context.submit(new PrepareRunner(context, conn, buffer)); context.runAsync(new PrepareRunner(context, conn, buffer));
} catch (Exception e) { } catch (Exception e) {
context.offerBuffer(buffer); context.offerBuffer(buffer);
} }
@@ -159,7 +160,7 @@ public abstract class ProtocolServer {
@Override @Override
public void completed(final AsynchronousSocketChannel channel, Void attachment) { public void completed(final AsynchronousSocketChannel channel, Void attachment) {
serchannel.accept(null, this); serchannel.accept(null, this);
context.submit(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null)); context.submitAsync(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null));
} }
@Override @Override

View File

@@ -11,6 +11,7 @@ import org.redkale.convert.bson.BsonConvert;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
/** /**
* 协议请求对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -10,6 +10,7 @@ import java.nio.channels.CompletionHandler;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
/** /**
* 协议响应对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -29,6 +30,8 @@ public abstract class Response<C extends Context, R extends Request<C>> {
private boolean inited = true; private boolean inited = true;
protected Object output; //输出的结果对象
protected BiConsumer<R, Response<C, R>> recycleListener; protected BiConsumer<R, Response<C, R>> recycleListener;
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() { private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
@@ -54,29 +57,26 @@ public abstract class Response<C extends Context, R extends Request<C>> {
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() { private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
@Override @Override
public void completed(Integer result, ByteBuffer[] attachments) { public void completed(final Integer result, final ByteBuffer[] attachments) {
int index = -1; int index = -1;
for (int i = 0; i < attachments.length; i++) { for (int i = 0; i < attachments.length; i++) {
if (attachments[i].hasRemaining()) { if (attachments[i].hasRemaining()) {
index = i; index = i;
break; break;
} else {
context.offerBuffer(attachments[i]);
} }
} }
if (index == 0) { if (index >= 0) {
channel.write(attachments, attachments, this); channel.write(attachments, index, attachments.length - index, attachments, this);
} else if (index > 0) {
ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index];
System.arraycopy(attachments, index, newattachs, 0, newattachs.length);
channel.write(newattachs, newattachs, this);
} else { } else {
for (ByteBuffer attachment : attachments) {
context.offerBuffer(attachment);
}
finish(); finish();
} }
} }
@Override @Override
public void failed(Throwable exc, ByteBuffer[] attachments) { public void failed(Throwable exc, final ByteBuffer[] attachments) {
for (ByteBuffer attachment : attachments) { for (ByteBuffer attachment : attachments) {
context.offerBuffer(attachment); context.offerBuffer(attachment);
} }
@@ -113,10 +113,11 @@ public abstract class Response<C extends Context, R extends Request<C>> {
} }
recycleListener = null; recycleListener = null;
} }
this.output = null;
request.recycle(); request.recycle();
if (channel != null) { if (channel != null) {
if (keepAlive) { if (keepAlive) {
this.context.submit(new PrepareRunner(context, channel, null)); this.context.runAsync(new PrepareRunner(context, channel, null));
} else { } else {
try { try {
if (channel.isOpen()) channel.close(); if (channel.isOpen()) channel.close();
@@ -143,30 +144,60 @@ public abstract class Response<C extends Context, R extends Request<C>> {
this.recycleListener = recycleListener; this.recycleListener = recycleListener;
} }
public Object getOutput() {
return output;
}
/**
* 是否已关闭
*
* @return boolean
*/
public boolean isClosed() {
return !this.inited;
}
public void finish() { public void finish() {
this.finish(false); this.finish(false);
} }
public void finish(boolean kill) { public void finish(boolean kill) {
if (!this.inited) return; //避免重复关闭
//System.println("耗时: " + (System.currentTimeMillis() - request.createtime)); //System.println("耗时: " + (System.currentTimeMillis() - request.createtime));
if (kill) refuseAlive(); if (kill) refuseAlive();
this.context.responsePool.offer(this); this.context.responsePool.offer(this);
} }
public void finish(final byte[] bs) {
if (!this.inited) return; //避免重复关闭
if (this.context.bufferCapacity == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
buffer.flip();
this.finish(buffer);
} else {
this.finish(ByteBuffer.wrap(bs));
}
}
public void finish(ByteBuffer buffer) { public void finish(ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffer, buffer, finishHandler); this.channel.write(buffer, buffer, finishHandler);
} }
public void finish(boolean kill, ByteBuffer buffer) { public void finish(boolean kill, ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive(); if (kill) refuseAlive();
this.channel.write(buffer, buffer, finishHandler); this.channel.write(buffer, buffer, finishHandler);
} }
public void finish(ByteBuffer... buffers) { public void finish(ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffers, buffers, finishHandler2); this.channel.write(buffers, buffers, finishHandler2);
} }
public void finish(boolean kill, ByteBuffer... buffers) { public void finish(boolean kill, ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive(); if (kill) refuseAlive();
this.channel.write(buffers, buffers, finishHandler2); this.channel.write(buffers, buffers, finishHandler2);
} }

View File

@@ -9,6 +9,7 @@ import org.redkale.util.AnyValue;
import java.io.IOException; import java.io.IOException;
/** /**
* 协议请求处理类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -44,7 +44,7 @@ public final class Transport {
protected final String name; //即<group>的name属性 protected final String name; //即<group>的name属性
protected final String kind; //即<group>的kind属性 protected final String subprotocol; //即<group>的subprotocol属性
protected final boolean tcp; protected final boolean tcp;
@@ -62,16 +62,16 @@ public final class Transport {
protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>();
public Transport(String name, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool, public Transport(String name, WatchFactory watch, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) { final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this(name, DEFAULT_PROTOCOL, watch, kind, transportBufferPool, transportChannelGroup, clientAddress, addresses); this(name, DEFAULT_PROTOCOL, watch, subprotocol, transportBufferPool, transportChannelGroup, clientAddress, addresses);
} }
public Transport(String name, String protocol, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool, public Transport(String name, String protocol, WatchFactory watch, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) { final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this.name = name; this.name = name;
this.watch = watch; this.watch = watch;
this.kind = kind == null ? "" : kind.trim(); this.subprotocol = subprotocol == null ? "" : subprotocol.trim();
this.protocol = protocol; this.protocol = protocol;
this.tcp = "TCP".equalsIgnoreCase(protocol); this.tcp = "TCP".equalsIgnoreCase(protocol);
this.group = transportChannelGroup; this.group = transportChannelGroup;
@@ -83,14 +83,17 @@ public final class Transport {
public Transport(final Collection<Transport> transports) { public Transport(final Collection<Transport> transports) {
Transport first = null; Transport first = null;
List<String> tmpgroup = new ArrayList<>(); List<String> tmpgroup = new ArrayList<>();
for (Transport t : transports) { if (transports != null) {
if (first == null) first = t; for (Transport t : transports) {
tmpgroup.add(t.name); if (first == null) first = t;
tmpgroup.add(t.name);
}
} }
if (first == null) throw new NullPointerException("Collection<Transport> is null or empty");
//必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name //必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name
this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";")); this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";"));
this.watch = first.watch; this.watch = first.watch;
this.kind = first.kind; this.subprotocol = first.subprotocol;
this.protocol = first.protocol; this.protocol = first.protocol;
this.tcp = "TCP".equalsIgnoreCase(first.protocol); this.tcp = "TCP".equalsIgnoreCase(first.protocol);
this.group = first.group; this.group = first.group;
@@ -118,8 +121,8 @@ public final class Transport {
return name; return name;
} }
public String getKind() { public String getSubprotocol() {
return kind; return subprotocol;
} }
public void close() { public void close() {
@@ -162,7 +165,7 @@ public final class Transport {
public AsyncConnection pollConnection(SocketAddress addr) { public AsyncConnection pollConnection(SocketAddress addr) {
if (addr == null && remoteAddres.length == 1) addr = remoteAddres[0]; if (addr == null && remoteAddres.length == 1) addr = remoteAddres[0];
final boolean rand = addr == null; final boolean rand = addr == null;
if (rand && remoteAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") has no remoteAddress list"); if (rand && remoteAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") have no remoteAddress list");
try { try {
if (tcp) { if (tcp) {
AsynchronousSocketChannel channel = null; AsynchronousSocketChannel channel = null;

View File

@@ -8,8 +8,11 @@ package org.redkale.net;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
* 协议处理的自定义线程类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class WorkThread extends Thread { public class WorkThread extends Thread {
@@ -22,8 +25,8 @@ public class WorkThread extends Thread {
this.setDaemon(true); this.setDaemon(true);
} }
public void submit(Runnable runner) { public void runAsync(Runnable runner) {
executor.submit(runner); executor.execute(runner);
} }
public ExecutorService getExecutor() { public ExecutorService getExecutor() {

View File

@@ -22,8 +22,8 @@ public class DefaultRestServlet extends RestHttpServlet<Object> {
} }
@Override @Override
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException { public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
return true; next.execute(request, response);
} }
} }

View File

@@ -66,8 +66,8 @@ public abstract class HttpBaseServlet extends HttpServlet {
} }
/** /**
* 配合 &#64;WebAction 使用。 * 配合 &#64;WebMapping 使用。
* 用于对&#64;WebAction方法中参数描述 * 用于对&#64;WebMapping方法中参数描述
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -89,6 +89,8 @@ public abstract class HttpBaseServlet extends HttpServlet {
ParamSourceType src() default ParamSourceType.PARAMETER; //参数来源类型 ParamSourceType src() default ParamSourceType.PARAMETER; //参数来源类型
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
boolean required() default true; //参数是否必传
} }
@Documented @Documented
@@ -99,6 +101,34 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebParam[] value(); WebParam[] value();
} }
/**
* 使用 WebMapping 替代。
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Deprecated
@Documented
@Target({METHOD})
@Retention(RUNTIME)
protected @interface WebAction {
int actionid() default 0;
String url();
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法
String comment() default ""; //备注描述
boolean inherited() default true; //是否能被继承, 当 HttpBaseServlet 被继承后该方法是否能被子类继承
String result() default "Object"; //输出结果的数据类型
Class[] results() default {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
}
/** /**
* 配合 HttpBaseServlet 使用。 * 配合 HttpBaseServlet 使用。
* 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式 * 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式
@@ -111,7 +141,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
@Documented @Documented
@Target({METHOD}) @Target({METHOD})
@Retention(RUNTIME) @Retention(RUNTIME)
protected @interface WebAction { protected @interface WebMapping {
int actionid() default 0; int actionid() default 0;
@@ -121,13 +151,16 @@ public abstract class HttpBaseServlet extends HttpServlet {
String comment() default ""; //备注描述 String comment() default ""; //备注描述
boolean inherited() default true; //是否能被继承, 当 HttpBaseServlet 被继承后该方法是否能被子类继承
String result() default "Object"; //输出结果的数据类型 String result() default "Object"; //输出结果的数据类型
Class[] results() default {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
} }
/** /**
* 配合 HttpBaseServlet 使用。 * 配合 HttpBaseServlet 使用。
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值timeout=15秒)。 * 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
* 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。 * 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。
* *
* <p> * <p>
@@ -145,42 +178,127 @@ public abstract class HttpBaseServlet extends HttpServlet {
* *
* @return 超时秒数 * @return 超时秒数
*/ */
int timeout() default 15; int seconds() default 15;
} }
private Map.Entry<String, Entry>[] actions; private Map.Entry<String, Entry>[] mappings;
public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException { private final HttpServlet authSuccessServlet = new HttpServlet() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
Entry entry = (Entry) request.attachment;
if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
return;
}
response.setBufferHandler(entry.cacheHandler);
}
entry.servlet.execute(request, response);
}
};
private final HttpServlet preSuccessServlet = new HttpServlet() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
for (Map.Entry<String, Entry> en : mappings) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
request.attachment = entry;
if (entry.ignore) {
authSuccessServlet.execute(request, response);
} else {
authenticate(entry.moduleid, entry.actionid, request, response, authSuccessServlet);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
}
};
/**
* <p>
* 预执行方法在execute方法之前运行通常用于常规统计或基础检测例如 : <br>
* <blockquote><pre>
* &#64;Override
* public void preExecute(final HttpRequest request, final HttpResponse response, HttpServlet next) throws IOException {
* if (finer) response.setRecycleListener((req, resp) -&#62; { //记录处理时间比较长的请求
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
* if (e &#62; 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
* });
* next.execute(request, response);
* }
* </pre></blockquote>
* <p>
*
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @throws IOException IOException
*/
public void preExecute(HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
next.execute(request, response);
}
/**
* 使用 public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException 代替
*
* @param moduleid int
* @param actionid int
* @param request HttpRequest
* @param response HttpResponse
*
* @return boolean
* @throws IOException IOException
* @deprecated
*/
@Deprecated
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true; return true;
} }
/**
* <p>
* 用户登录或权限验证, 没有注解为&#64;AuthIgnore 的方法会执行authenticate方法, 若验证成功则必须调用next.execute(request, response);进行下一步操作, 例如: <br>
* <blockquote><pre>
* &#64;Override
* public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
* UserInfo info = currentUser(request);
* if (info == null) {
* response.finishJson(RET_UNLOGIN);
* return;
* } else if (!info.checkAuth(module, actionid)) {
* response.finishJson(RET_AUTHILLEGAL);
* return;
* }
* next.execute(request, response);
* }
* </pre></blockquote>
* <p>
*
*
* @param moduleid 模块ID来自&#64;WebServlet.moduleid()
* @param actionid 操作ID来自&#64;WebMapping.actionid()
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @throws IOException IOException
*/
public abstract void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException;
@Override @Override
public final void execute(HttpRequest request, HttpResponse response) throws IOException { public final void execute(HttpRequest request, HttpResponse response) throws IOException {
if (!preExecute(request, response)) return; preExecute(request, response, preSuccessServlet);
for (Map.Entry<String, Entry> en : actions) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
if (entry.cachetimeout > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
return;
}
response.setBufferHandler(entry.cacheHandler);
}
entry.servlet.execute(request, response);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
} }
public final void preInit(HttpContext context, AnyValue config) { public final void preInit(HttpContext context, AnyValue config) {
@@ -188,20 +306,18 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebServlet ws = this.getClass().getAnnotation(WebServlet.class); WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = ""; if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load(); HashMap<String, Entry> map = load();
this.actions = new Map.Entry[map.size()]; this.mappings = new Map.Entry[map.size()];
int i = -1; int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) { for (Map.Entry<String, Entry> en : map.entrySet()) {
actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue()); mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
} }
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query //必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
Arrays.sort(actions, (o1, o2) -> o2.getKey().compareTo(o1.getKey())); Arrays.sort(mappings, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
} }
public final void postDestroy(HttpContext context, AnyValue config) { public final void postDestroy(HttpContext context, AnyValue config) {
} }
public abstract boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException;
protected void setHeader(HttpRequest request, String name, Serializable value) { protected void setHeader(HttpRequest request, String name, Serializable value) {
request.header.setValue(name, String.valueOf(value)); request.header.setValue(name, String.valueOf(value));
} }
@@ -219,29 +335,40 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebServlet module = this.getClass().getAnnotation(WebServlet.class); WebServlet module = this.getClass().getAnnotation(WebServlet.class);
final int serviceid = module == null ? 0 : module.moduleid(); final int serviceid = module == null ? 0 : module.moduleid();
final HashMap<String, Entry> map = new HashMap<>(); final HashMap<String, Entry> map = new HashMap<>();
Set<String> nameset = new HashSet<>(); HashMap<String, Class> nameset = new HashMap<>();
for (final Method method : this.getClass().getMethods()) { final Class selfClz = this.getClass();
//----------------------------------------------- Class clz = this.getClass();
String methodname = method.getName(); do {
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue; if (Modifier.isAbstract(clz.getModifiers())) break;
//----------------------------------------------- for (final Method method : clz.getMethods()) {
Class[] paramTypes = method.getParameterTypes(); //-----------------------------------------------
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class String methodname = method.getName();
|| paramTypes[1] != HttpResponse.class) continue; if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
//----------------------------------------------- //-----------------------------------------------
Class[] exps = method.getExceptionTypes(); Class[] paramTypes = method.getParameterTypes();
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue; if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
//----------------------------------------------- || paramTypes[1] != HttpResponse.class) continue;
//-----------------------------------------------
Class[] exps = method.getExceptionTypes();
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
final WebAction action = method.getAnnotation(WebAction.class); final WebMapping mapping = method.getAnnotation(WebMapping.class);
if (action == null) continue; final WebAction action = method.getAnnotation(WebAction.class);
final int actionid = action.actionid(); if (mapping == null && action == null) continue;
final String name = action.url().trim(); final boolean inherited = mapping == null ? action.inherited() : mapping.inherited();
if (!inherited && selfClz != clz) continue; //忽略不被继承的方法
if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")"); final int actionid = mapping == null ? action.actionid() : mapping.actionid();
nameset.add(name); final String name = mapping == null ? action.url().trim() : mapping.url().trim();
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method))); final String[] methods = mapping == null ? action.methods() : mapping.methods();
} if (nameset.containsKey(name)) {
if (nameset.get(name) != clz) continue;
throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + WebMapping.class.getSimpleName() + "(" + name + ")");
}
nameset.put(name, clz);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, methods, method, createHttpServlet(method)));
}
} while ((clz = clz.getSuperclass()) != HttpBaseServlet.class);
return map; return map;
} }
@@ -260,7 +387,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
try { try {
Class.forName(newDynName.replace('/', '.')); Class.forName(newDynName.replace('/', '.'));
newDynName += "_" + (++i); newDynName += "_" + (++i);
} catch (Exception ex) { } catch (Throwable ex) {
break; break;
} }
} }
@@ -335,9 +462,9 @@ public abstract class HttpBaseServlet extends HttpServlet {
this.servlet = servlet; this.servlet = servlet;
this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null; this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null;
HttpCacheable hc = method.getAnnotation(HttpCacheable.class); HttpCacheable hc = method.getAnnotation(HttpCacheable.class);
this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000; this.cacheseconds = hc == null ? 0 : hc.seconds() * 1000;
this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null; this.cache = cacheseconds > 0 ? new ConcurrentHashMap() : null;
this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> { this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus(); int status = response.getStatus();
if (status != 200) return null; if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers); CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
@@ -362,7 +489,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
public final ConcurrentHashMap<String, CacheEntry> cache; public final ConcurrentHashMap<String, CacheEntry> cache;
public final int cachetimeout; public final int cacheseconds;
public final boolean ignore; public final boolean ignore;

View File

@@ -16,6 +16,7 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* HTTP服务的上下文对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -27,10 +28,10 @@ public class HttpContext extends Context {
protected final SecureRandom random = new SecureRandom(); protected final SecureRandom random = new SecureRandom();
public HttpContext(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, public HttpContext(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool,
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare, ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) { WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) {
super(serverStartTime, logger, executor, bufferCapacity, bufferPool, responsePool, maxbody, charset, super(serverStartTime, logger, executor, bufferCapacity, bufferPool, responsePool, maxbody, charset,
address, prepare, watch, readTimeoutSecond, writeTimeoutSecond); address, prepare, watch, readTimeoutSecond, writeTimeoutSecond);
random.setSeed(Math.abs(System.nanoTime())); random.setSeed(Math.abs(System.nanoTime()));
} }

View File

@@ -17,6 +17,8 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* HTTP Servlet的总入口请求在HttpPrepareServlet中进行分流。 <br>
* 一个HttpServer只有一个HttpPrepareServlet 用于管理所有HttpServlet。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -35,7 +37,8 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
@Override @Override
public void init(HttpContext context, AnyValue config) { public void init(HttpContext context, AnyValue config) {
this.servlets.forEach(s -> { Collection<HttpServlet> servlets = getServlets();
servlets.forEach(s -> {
if (s instanceof WebSocketServlet) { if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).preInit(context, getServletConf(s)); ((WebSocketServlet) s).preInit(context, getServletConf(s));
} else if (s instanceof HttpBaseServlet) { } else if (s instanceof HttpBaseServlet) {
@@ -45,7 +48,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
}); });
final WatchFactory watch = context.getWatchFactory(); final WatchFactory watch = context.getWatchFactory();
if (watch != null) { if (watch != null) {
this.servlets.forEach(s -> { servlets.forEach(s -> {
watch.inject(s); watch.inject(s);
}); });
} }
@@ -69,7 +72,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
String resServlet = resConfig.getValue("servlet", HttpResourceServlet.class.getName()); String resServlet = resConfig.getValue("servlet", HttpResourceServlet.class.getName());
try { try {
this.resourceHttpServlet = (HttpServlet) Class.forName(resServlet).newInstance(); this.resourceHttpServlet = (HttpServlet) Class.forName(resServlet).newInstance();
} catch (Exception e) { } catch (Throwable e) {
this.resourceHttpServlet = new HttpResourceServlet(); this.resourceHttpServlet = new HttpResourceServlet();
logger.log(Level.WARNING, "init HttpResourceSerlvet(" + resServlet + ") error", e); logger.log(Level.WARNING, "init HttpResourceSerlvet(" + resServlet + ") error", e);
} }
@@ -80,7 +83,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
public void execute(HttpRequest request, HttpResponse response) throws IOException { public void execute(HttpRequest request, HttpResponse response) throws IOException {
try { try {
final String uri = request.getRequestURI(); final String uri = request.getRequestURI();
Servlet<HttpContext, HttpRequest, HttpResponse> servlet = this.mappings.isEmpty() ? null : this.mappings.get(uri); Servlet<HttpContext, HttpRequest, HttpResponse> servlet = mappingServlet(uri);
if (servlet == null && this.regArray != null) { if (servlet == null && this.regArray != null) {
for (SimpleEntry<Predicate<String>, HttpServlet> en : regArray) { for (SimpleEntry<Predicate<String>, HttpServlet> en : regArray) {
if (en.getKey().test(uri)) { if (en.getKey().test(uri)) {
@@ -89,6 +92,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
} }
//找不到匹配的HttpServlet则使用静态资源HttpResourceServlet
if (servlet == null) servlet = this.resourceHttpServlet; if (servlet == null) servlet = this.resourceHttpServlet;
servlet.execute(request, response); servlet.execute(request, response);
} catch (Exception e) { } catch (Exception e) {
@@ -97,6 +101,14 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param prefix url前缀
* @param conf 配置信息
* @param mappings 匹配规则
*/
@Override @Override
public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) { public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) {
if (prefix == null) prefix = ""; if (prefix == null) prefix = "";
@@ -107,12 +119,12 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix
} }
} }
synchronized (allMapStrings) { synchronized (allMapStrings) { //需要整段锁住
for (String mapping : mappings) { for (String mapping : mappings) {
if (mapping == null) continue; if (mapping == null) continue;
if (!prefix.toString().isEmpty()) mapping = prefix + mapping; if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
if (contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式)) if (Utility.contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
if (mapping.charAt(0) != '^') mapping = '^' + mapping; if (mapping.charAt(0) != '^') mapping = '^' + mapping;
if (mapping.endsWith("/*")) { if (mapping.endsWith("/*")) {
mapping = mapping.substring(0, mapping.length() - 1) + ".*"; mapping = mapping.substring(0, mapping.length() - 1) + ".*";
@@ -127,7 +139,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
regArray[regArray.length - 1] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet); regArray[regArray.length - 1] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
} }
} else if (mapping != null && !mapping.isEmpty()) { } else if (mapping != null && !mapping.isEmpty()) {
super.mappings.put(mapping, servlet); putMapping(mapping, servlet);
} }
if (this.allMapStrings.containsKey(mapping)) { if (this.allMapStrings.containsKey(mapping)) {
Class old = this.allMapStrings.get(mapping); Class old = this.allMapStrings.get(mapping);
@@ -137,26 +149,26 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
setServletConf(servlet, conf); setServletConf(servlet, conf);
servlet._prefix = prefix.toString(); servlet._prefix = prefix.toString();
this.servlets.add(servlet); putServlet(servlet);
} }
} }
private static boolean contains(String string, char... values) { /**
if (string == null) return false; * 设置静态资源HttpServlet
for (char ch : Utility.charArray(string)) { *
for (char ch2 : values) { * @param servlet HttpServlet
if (ch == ch2) return true; */
}
}
return false;
}
public void setResourceServlet(HttpServlet servlet) { public void setResourceServlet(HttpServlet servlet) {
if (servlet != null) { if (servlet != null) {
this.resourceHttpServlet = servlet; this.resourceHttpServlet = servlet;
} }
} }
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() { public HttpServlet getResourceServlet() {
return this.resourceHttpServlet; return this.resourceHttpServlet;
} }
@@ -164,7 +176,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
@Override @Override
public void destroy(HttpContext context, AnyValue config) { public void destroy(HttpContext context, AnyValue config) {
this.resourceHttpServlet.destroy(context, config); this.resourceHttpServlet.destroy(context, config);
this.servlets.forEach(s -> { getServlets().forEach(s -> {
s.destroy(context, getServletConf(s)); s.destroy(context, getServletConf(s));
if (s instanceof WebSocketServlet) { if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).postDestroy(context, getServletConf(s)); ((WebSocketServlet) s).postDestroy(context, getServletConf(s));

View File

@@ -22,7 +22,7 @@ import org.redkale.util.ByteArray;
* 例如简单的翻页查询 <br> * 例如简单的翻页查询 <br>
* /pipes/record/query/offset:0/limit:20 <br> * /pipes/record/query/offset:0/limit:20 <br>
* 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br> * 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br>
* 获取行数: int limit = request.getRequstURIPath("limit:", 10); * 获取行数: int limit = request.getRequstURIPath("limit:", 10); <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -66,6 +66,8 @@ public class HttpRequest extends Request<HttpContext> {
private final String remoteAddrHeader; private final String remoteAddrHeader;
Object attachment; //供 HttpBaseServlet传递Entry使用
public HttpRequest(HttpContext context, String remoteAddrHeader) { public HttpRequest(HttpContext context, String remoteAddrHeader) {
super(context); super(context);
this.remoteAddrHeader = remoteAddrHeader; this.remoteAddrHeader = remoteAddrHeader;
@@ -236,7 +238,7 @@ public class HttpRequest extends Request<HttpContext> {
* @return 地址 * @return 地址
*/ */
public SocketAddress getRemoteAddress() { public SocketAddress getRemoteAddress() {
return this.channel.getRemoteAddress(); return this.channel == null || !this.channel.isOpen() ? null : this.channel.getRemoteAddress();
} }
/** /**
@@ -336,6 +338,8 @@ public class HttpRequest extends Request<HttpContext> {
this.boundary = false; this.boundary = false;
this.bodyparsed = false; this.bodyparsed = false;
this.attachment = null;
this.header.clear(); this.header.clear();
this.params.clear(); this.params.clear();
this.array.clear(); this.array.clear();
@@ -352,7 +356,7 @@ public class HttpRequest extends Request<HttpContext> {
public String getSessionid(boolean create) { public String getSessionid(boolean create) {
String sessionid = getCookie(SESSIONID_NAME, null); String sessionid = getCookie(SESSIONID_NAME, null);
if (create && (sessionid == null || sessionid.isEmpty())) { if (create && (sessionid == null || sessionid.isEmpty())) {
sessionid = ((HttpContext) context).createSessionid(); sessionid = context.createSessionid();
this.newsessionid = sessionid; this.newsessionid = sessionid;
} }
return sessionid; return sessionid;
@@ -368,6 +372,18 @@ public class HttpRequest extends Request<HttpContext> {
return newsessionid; return newsessionid;
} }
/**
* 指定值更新sessionid
*
* @param newsessionid 新sessionid值
*
* @return 新的sessionid值
*/
public String changeSessionid(String newsessionid) {
this.newsessionid = newsessionid == null ? context.createSessionid() : newsessionid.trim();
return newsessionid;
}
/** /**
* 使sessionid失效 * 使sessionid失效
*/ */
@@ -500,6 +516,123 @@ public class HttpRequest extends Request<HttpContext> {
return requestURI.substring(requestURI.lastIndexOf('/') + 1); return requestURI.substring(requestURI.lastIndexOf('/') + 1);
} }
/**
* 获取请求URL最后的一个/后面的部分的short值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2
*
* @param defvalue 默认short值
*
* @return short值
*/
public short getRequstURILastPath(short defvalue) {
String val = getRequstURILastPath();
if (val.isEmpty()) return defvalue;
return val.isEmpty() ? defvalue : Short.parseShort(val);
}
/**
* 获取请求URL最后的一个/后面的部分的short值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: short type = request.getRequstURILastPath(16, (short)0); //type = 2
*
* @param radix 进制数
* @param defvalue 默认short值
*
* @return short值
*/
public short getRequstURILastPath(int radix, short defvalue) {
String val = getRequstURILastPath();
if (val.isEmpty()) return defvalue;
return val.isEmpty() ? defvalue : Short.parseShort(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: int type = request.getRequstURILastPath(0); //type = 2
*
* @param defvalue 默认int值
*
* @return int值
*/
public int getRequstURILastPath(int defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Integer.parseInt(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: int type = request.getRequstURILastPath(16, 0); //type = 2
*
* @param radix 进制数
* @param defvalue 默认int值
*
* @return int值
*/
public int getRequstURILastPath(int radix, int defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Integer.parseInt(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的float值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: float type = request.getRequstURILastPath(0.0f); //type = 2.0f
*
* @param defvalue 默认float值
*
* @return float值
*/
public float getRequstURILastPath(float defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Float.parseFloat(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2
*
* @param defvalue 默认long值
*
* @return long值
*/
public long getRequstURILastPath(long defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Long.parseLong(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: long type = request.getRequstURILastPath(16, 0L); //type = 2
*
* @param radix 进制数
* @param defvalue 默认long值
*
* @return long值
*/
public long getRequstURILastPath(int radix, long defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Long.parseLong(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的double值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0
*
* @param defvalue 默认double值
*
* @return double值
*/
public double getRequstURILastPath(double defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Double.parseDouble(val);
}
/** /**
* *
* 从prefix之后截取getRequestURI再对"/"进行分隔 * 从prefix之后截取getRequestURI再对"/"进行分隔
@@ -1109,17 +1242,18 @@ public class HttpRequest extends Request<HttpContext> {
* @return Flipper翻页对象 * @return Flipper翻页对象
*/ */
public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) { public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) {
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name); org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name);
if (flipper == null) { if (flipper == null) {
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
int limit = getRequstURIPath("limit:", maxLimit); int limit = getRequstURIPath("limit:", maxLimit);
int offset = getRequstURIPath("offset:", 0); int offset = getRequstURIPath("offset:", 0);
String sort = getRequstURIPath("sort:", ""); String sort = getRequstURIPath("sort:", "");
if (limit > 0) flipper = new org.redkale.source.Flipper(limit, offset, sort); if (limit > 0) flipper = new org.redkale.source.Flipper(limit, offset, sort);
} else if (flipper.getLimit() < 1 || flipper.getLimit() > maxLimit) { } else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) {
flipper.setLimit(maxLimit); flipper.setLimit(maxLimit);
} }
if (flipper != null || !needcreate) return flipper; if (flipper != null || !needcreate) return flipper;
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
return new org.redkale.source.Flipper(maxLimit); return new org.redkale.source.Flipper(maxLimit);
} }
} }

View File

@@ -18,6 +18,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue; import org.redkale.util.AnyValue;
/** /**
* 静态资源HttpServlet
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -13,7 +13,9 @@ import java.nio.channels.*;
import java.nio.file.*; import java.nio.file.*;
import java.text.*; import java.text.*;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
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.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
@@ -21,9 +23,9 @@ import org.redkale.util.AnyValue.Entry;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。 * Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。 <br>
* 同时提供发送json的系列接口: public void finishJson(Type type, Object obj) * 同时提供发送json的系列接口: public void finishJson(Type type, Object obj) <br>
* Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。 * Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -184,14 +186,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @return HttpResponse * @return HttpResponse
*/ */
public HttpResponse addCookie(HttpCookie... cookies) { public HttpResponse addCookie(HttpCookie... cookies) {
if (this.cookies == null) { this.cookies = Utility.append(this.cookies, cookies);
this.cookies = cookies;
} else {
HttpCookie[] news = new HttpCookie[this.cookies.length + cookies.length];
System.arraycopy(this.cookies, 0, news, 0, this.cookies.length);
System.arraycopy(cookies, 0, news, this.cookies.length, cookies.length);
this.cookies = news;
}
return this; return this;
} }
@@ -203,21 +198,30 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @return HttpResponse * @return HttpResponse
*/ */
public HttpResponse addCookie(Collection<HttpCookie> cookies) { public HttpResponse addCookie(Collection<HttpCookie> cookies) {
if (cookies == null || cookies.isEmpty()) return this; this.cookies = Utility.append(this.cookies, cookies);
if (this.cookies == null) {
this.cookies = cookies.toArray(new HttpCookie[cookies.size()]);
} else {
HttpCookie[] news = new HttpCookie[this.cookies.length + cookies.size()];
System.arraycopy(this.cookies, 0, news, 0, this.cookies.length);
int i = this.cookies.length;
for (HttpCookie cookie : cookies) {
news[i++] = cookie;
}
this.cookies = news;
}
return this; return this;
} }
/**
* 创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出
*
* @return AsyncHandler
*/
public AsyncHandler createAsyncHandler() {
return AsyncHandler.create((v, a) -> {
if (v instanceof org.redkale.service.RetResult) {
finishJson((org.redkale.service.RetResult) v);
} else if (v instanceof CharSequence) {
finish(String.valueOf(v));
} else {
finishJson(v);
}
}, (t, a) -> {
request.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, t);
finish(500, null);
});
}
/** /**
* 将对象以JSON格式输出 * 将对象以JSON格式输出
* *
@@ -225,6 +229,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final Object obj) { public void finishJson(final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = obj;
finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), obj)); finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), obj));
} }
@@ -236,6 +241,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final JsonConvert convert, final Object obj) { public void finishJson(final JsonConvert convert, final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = obj;
finish(convert.convertTo(context.getBufferSupplier(), obj)); finish(convert.convertTo(context.getBufferSupplier(), obj));
} }
@@ -247,6 +253,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final Type type, final Object obj) { public void finishJson(final Type type, final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
this.output = obj;
finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), type, obj)); finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), type, obj));
} }
@@ -259,6 +266,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final JsonConvert convert, final Type type, final Object obj) { public void finishJson(final JsonConvert convert, final Type type, final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = obj;
finish(convert.convertTo(context.getBufferSupplier(), type, obj)); finish(convert.convertTo(context.getBufferSupplier(), type, obj));
} }
@@ -269,6 +277,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final Object... objs) { public void finishJson(final Object... objs) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = objs;
finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), objs)); finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), objs));
} }
@@ -279,6 +288,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final org.redkale.service.RetResult ret) { public void finishJson(final org.redkale.service.RetResult ret) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = ret;
if (ret != null && !ret.isSuccess()) { if (ret != null && !ret.isSuccess()) {
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());
@@ -294,6 +304,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret) { public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = ret;
if (ret != null && !ret.isSuccess()) { if (ret != null && !ret.isSuccess()) {
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());
@@ -302,26 +313,59 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
} }
/** /**
* 将对象以JavaScript格式输出 * 将CompletableFuture的结果对象以JSON格式输出
* *
* @param var js变量名 * @param future 输出对象的句柄
* @param result 输出对象
*/ */
public void finishJsResult(String var, Object result) { public void finishJson(final CompletableFuture future) {
this.contentType = "application/javascript; charset=utf-8"; finishJson(request.getJsonConvert(), future);
finish("var " + var + " = " + request.getJsonConvert().convertTo(result) + ";");
} }
/** /**
* 将对象以JavaScript格式输出 * 将CompletableFuture的结果对象以JSON格式输出
* *
* @param jsonConvert 指定的JsonConvert * @param convert 指定的JsonConvert
* @param var js变量名 * @param future 输出对象的句柄
* @param result 输出对象
*/ */
public void finishJsResult(JsonConvert jsonConvert, String var, Object result) { public void finishJson(final JsonConvert convert, final CompletableFuture future) {
this.contentType = "application/javascript; charset=utf-8"; future.whenComplete((v, e) -> {
finish("var " + var + " = " + jsonConvert.convertTo(result) + ";"); if (e != null) {
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
finish(500, null);
return;
}
if (v instanceof CharSequence) {
finish(v.toString());
} else if (v instanceof org.redkale.service.RetResult) {
finishJson(convert, (org.redkale.service.RetResult) v);
} else {
finishJson(convert, v);
}
});
}
/**
* 将CompletableFuture的结果对象以JSON格式输出
*
* @param convert 指定的JsonConvert
* @param type 指定的类型
* @param future 输出对象的句柄
*/
public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future) {
future.whenComplete((v, e) -> {
if (e != null) {
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
finish(500, null);
return;
}
if (v instanceof CharSequence) {
finish(v.toString());
} else if (v instanceof org.redkale.service.RetResult) {
finishJson(convert, (org.redkale.service.RetResult) v);
} else {
finishJson(convert, type, v);
}
});
} }
/** /**
@@ -330,6 +374,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param obj 输出内容 * @param obj 输出内容
*/ */
public void finish(String obj) { public void finish(String obj) {
if (isClosed()) return;
if (this.recycleListener != null) this.output = obj;
if (obj == null || obj.isEmpty()) { if (obj == null || obj.isEmpty()) {
final ByteBuffer headbuf = createHeader(); final ByteBuffer headbuf = createHeader();
headbuf.flip(); headbuf.flip();
@@ -370,6 +416,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param message 输出内容 * @param message 输出内容
*/ */
public void finish(int status, String message) { public void finish(int status, String message) {
if (isClosed()) return;
this.status = status; this.status = status;
if (status != 200) super.refuseAlive(); if (status != 200) super.refuseAlive();
finish(message); finish(message);
@@ -389,6 +436,24 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
super.finish(buffer404.duplicate()); super.finish(buffer404.duplicate());
} }
/**
* 将指定byte[]按响应结果输出
*
* @param bs 输出内容
*/
@Override
public void finish(final byte[] bs) {
if (isClosed()) return; //避免重复关闭
if (this.context.getBufferCapacity() == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
buffer.flip();
this.finish(false, buffer);
} else {
this.finish(false, ByteBuffer.wrap(bs));
}
}
/** /**
* 将指定ByteBuffer按响应结果输出 * 将指定ByteBuffer按响应结果输出
* *
@@ -407,6 +472,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 (!this.headsended) { if (!this.headsended) {
this.contentLength = buffer == null ? 0 : buffer.remaining(); this.contentLength = buffer == null ? 0 : buffer.remaining();
ByteBuffer headbuf = createHeader(); ByteBuffer headbuf = createHeader();
@@ -439,6 +505,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
@Override @Override
public void finish(boolean kill, ByteBuffer... buffers) { public void finish(boolean kill, ByteBuffer... buffers) {
if (isClosed()) return; //避免重复关闭
if (bufferHandler != null) { if (bufferHandler != null) {
ByteBuffer[] bufs = bufferHandler.execute(this, buffers); ByteBuffer[] bufs = bufferHandler.execute(this, buffers);
if (bufs != null) buffers = bufs; if (bufs != null) buffers = bufs;
@@ -473,7 +540,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param attachment 异步回调参数 * @param attachment 异步回调参数
* @param handler 异步回调函数 * @param handler 异步回调函数
*/ */
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler) { public <A> void sendBody(ByteBuffer buffer, A attachment, AsyncHandler<Integer, A> handler) {
if (!this.headsended) { if (!this.headsended) {
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();
@@ -488,6 +555,37 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
} }
} }
/**
* 异步输出指定内容
*
* @param <A> 泛型
* @param buffers 输出内容
* @param attachment 异步回调参数
* @param handler 异步回调函数
*/
public <A> void sendBody(ByteBuffer[] buffers, A attachment, AsyncHandler<Integer, A> handler) {
if (!this.headsended) {
if (this.contentLength < 0) {
int len = 0;
if (buffers != null && buffers.length > 0) {
for (ByteBuffer b : buffers) {
len += b.remaining();
}
}
this.contentLength = len;
}
ByteBuffer headbuf = createHeader();
headbuf.flip();
if (buffers == null || buffers.length == 0) {
super.send(headbuf, attachment, handler);
} else {
super.send(Utility.unshift(buffers, headbuf), attachment, handler);
}
} else {
super.send(buffers, attachment, handler);
}
}
/** /**
* 将指定文件按响应结果输出 * 将指定文件按响应结果输出
* *
@@ -812,7 +910,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
this.bufferHandler = bufferHandler; this.bufferHandler = bufferHandler;
} }
protected final class TransferFileHandler implements CompletionHandler<Integer, ByteBuffer> { protected final class TransferFileHandler implements AsyncHandler<Integer, ByteBuffer> {
private final AsynchronousFileChannel filechannel; private final AsynchronousFileChannel filechannel;

View File

@@ -16,6 +16,7 @@ import org.redkale.util.*;
import org.redkale.watch.WatchFactory; import org.redkale.watch.WatchFactory;
/** /**
* Http服务器
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -37,24 +38,88 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
super.init(config); super.init(config);
} }
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() {
return ((HttpPrepareServlet) this.prepare).resourceHttpServlet;
}
/**
* 添加HttpServlet
*
* @param prefix url前缀
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) { public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, prefix, null, mappings); this.prepare.addServlet(servlet, prefix, null, mappings);
return this; return this;
} }
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) { public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, null, null, mappings); this.prepare.addServlet(servlet, null, null, mappings);
return this; return this;
} }
public void addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) { /**
* 添加HttpServlet
*
* @param prefix url前缀
* @param servlet HttpServlet
* @param conf 配置信息
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) {
this.prepare.addServlet(servlet, prefix, conf, mappings); this.prepare.addServlet(servlet, prefix, conf, mappings);
return this;
} }
/**
* 添加RestHttpServlet
*
* @param <S> Service
* @param <T> RestHttpServlet
* @param name Service的资源名
* @param serviceType Service的类型
* @param service Service对象
* @param baseServletClass RestHttpServlet基类
* @param prefix url前缀
*
* @return RestHttpServlet
*/
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(String name, Class<S> serviceType, S service, Class<T> baseServletClass, String prefix) { public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(String name, Class<S> serviceType, S service, Class<T> baseServletClass, String prefix) {
return addRestServlet(name, serviceType, service, baseServletClass, prefix, null); return addRestServlet(name, serviceType, service, baseServletClass, prefix, null);
} }
/**
* 添加RestHttpServlet
*
* @param <S> Service
* @param <T> RestHttpServlet
* @param name Service的资源名
* @param serviceType Service的类型
* @param service Service对象
* @param baseServletClass RestHttpServlet基类
* @param prefix url前缀
* @param conf 配置信息
*
* @return RestHttpServlet
*/
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet( public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(
final String name, Class<S> serviceType, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) { final String name, Class<S> serviceType, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) {
RestHttpServlet servlet = null; RestHttpServlet servlet = null;

View File

@@ -8,6 +8,7 @@ package org.redkale.net.http;
import java.util.*; import java.util.*;
/** /**
* MimeType
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -100,6 +101,7 @@ public class MimeType {
contentTypes.put("oda", "application/oda"); contentTypes.put("oda", "application/oda");
contentTypes.put("ogg", "application/ogg"); contentTypes.put("ogg", "application/ogg");
contentTypes.put("out", "text/plain"); contentTypes.put("out", "text/plain");
contentTypes.put("pac", "application/x-javascript-config");
contentTypes.put("pbm", "image/x-portable-bitmap"); contentTypes.put("pbm", "image/x-portable-bitmap");
contentTypes.put("pct", "image/pict"); contentTypes.put("pct", "image/pict");
contentTypes.put("pdf", "application/pdf"); contentTypes.put("pdf", "application/pdf");

View File

@@ -15,6 +15,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
/** /**
* HTTP的文件上传请求的上下文对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -77,10 +78,21 @@ public final class MultiContext {
return null; return null;
} }
/**
* 判断请求是否包含上传文件
*
* @return boolean
*/
public boolean isMultipart() { public boolean isMultipart() {
return this.boundary != null; return this.boundary != null;
} }
/**
* 获取上传文件信息列表
*
* @return Iterable
* @throws IOException IOException
*/
public Iterable<MultiPart> parts() throws IOException { public Iterable<MultiPart> parts() throws IOException {
if (!isMultipart()) return emptyIterable; if (!isMultipart()) return emptyIterable;
final String boundarystr = "--" + this.boundary; final String boundarystr = "--" + this.boundary;

View File

@@ -11,6 +11,7 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import jdk.internal.org.objectweb.asm.*; import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.internal.org.objectweb.asm.Opcodes.*;
@@ -36,6 +37,8 @@ public final class Rest {
static final String REST_SERVICEMAP_FIELD_NAME = "_servicemap"; //如果只有name=""的Service资源则实例中_servicemap必须为null static final String REST_SERVICEMAP_FIELD_NAME = "_servicemap"; //如果只有name=""的Service资源则实例中_servicemap必须为null
private static final String REST_PARAMTYPES_FIELD_NAME = "_paramtypes"; //存在泛型的参数数组 Type[][] 第1维度是方法的下标 第二维度是参数的下标
private static final Set<String> EXCLUDERMETHODS = new HashSet<>(); private static final Set<String> EXCLUDERMETHODS = new HashSet<>();
static { static {
@@ -58,6 +61,42 @@ public final class Rest {
private Rest() { private Rest() {
} }
public static class MethodParamClassVisitor extends ClassVisitor {
private final Map<String, List<String>> fieldmap;
public MethodParamClassVisitor(int api, final Map<String, List<String>> fieldmap) {
super(api);
this.fieldmap = fieldmap;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (java.lang.reflect.Modifier.isStatic(access)) return null;
List<String> fieldnames = new ArrayList<>();
fieldmap.put(name + ":" + desc, fieldnames);
return new MethodVisitor(Opcodes.ASM5) {
@Override
public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
if (index > 0) fieldnames.add(name);
}
};
}
//返回的List中参数列表可能会比方法参数量多因为方法内的临时变量也会存入list中 所以需要list的元素集合比方法的参数多
public static Map<String, List<String>> getMethodParamNames(Class clazz) {
String n = clazz.getName();
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
Map<String, List<String>> map = new HashMap<>();
if (in == null) return map;
try {
new ClassReader(Utility.readBytesThenClose(in)).accept(new MethodParamClassVisitor(Opcodes.ASM5, map), 0);
} catch (Exception e) { //无需理会
}
return map;
}
}
static String getWebModuleName(Class<? extends Service> serviceType) { static String getWebModuleName(Class<? extends Service> serviceType) {
final RestService controller = serviceType.getAnnotation(RestService.class); final RestService controller = serviceType.getAnnotation(RestService.class);
if (controller == null) return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase(); if (controller == null) return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase();
@@ -72,17 +111,20 @@ public final class Rest {
if (!java.lang.reflect.Modifier.isPublic(mod)) return null; if (!java.lang.reflect.Modifier.isPublic(mod)) return null;
if (java.lang.reflect.Modifier.isAbstract(mod)) return null; if (java.lang.reflect.Modifier.isAbstract(mod)) return null;
final java.lang.reflect.Type futureRestOutputType = new TypeToken<CompletableFuture<RestOutput>>() {
}.getType();
final String serviceDesc = Type.getDescriptor(serviceType); final String serviceDesc = Type.getDescriptor(serviceType);
final String webServletDesc = Type.getDescriptor(WebServlet.class); final String webServletDesc = Type.getDescriptor(WebServlet.class);
final String reqDesc = Type.getDescriptor(HttpRequest.class); final String reqDesc = Type.getDescriptor(HttpRequest.class);
final String respDesc = Type.getDescriptor(HttpResponse.class); final String respDesc = Type.getDescriptor(HttpResponse.class);
final String retDesc = Type.getDescriptor(RetResult.class); final String retDesc = Type.getDescriptor(RetResult.class);
final String futureDesc = Type.getDescriptor(CompletableFuture.class);
final String flipperDesc = Type.getDescriptor(Flipper.class); final String flipperDesc = Type.getDescriptor(Flipper.class);
final String restoutputDesc = Type.getDescriptor(RestOutput.class); final String restoutputDesc = Type.getDescriptor(RestOutput.class);
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class); final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class); final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class);
final String cacheDesc = Type.getDescriptor(HttpBaseServlet.HttpCacheable.class); final String cacheDesc = Type.getDescriptor(HttpBaseServlet.HttpCacheable.class);
final String actionDesc = Type.getDescriptor(HttpBaseServlet.WebAction.class); final String mappingDesc = Type.getDescriptor(HttpBaseServlet.WebMapping.class);
final String webparamDesc = Type.getDescriptor(HttpBaseServlet.WebParam.class); final String webparamDesc = Type.getDescriptor(HttpBaseServlet.WebParam.class);
final String webparamsDesc = Type.getDescriptor(HttpBaseServlet.WebParams.class); final String webparamsDesc = Type.getDescriptor(HttpBaseServlet.WebParams.class);
final String sourcetypeDesc = Type.getDescriptor(HttpBaseServlet.ParamSourceType.class); final String sourcetypeDesc = Type.getDescriptor(HttpBaseServlet.ParamSourceType.class);
@@ -99,10 +141,7 @@ public final class Rest {
if (controller != null && controller.ignore()) return null; //标记为ignore=true不创建Servlet if (controller != null && controller.ignore()) return null; //标记为ignore=true不创建Servlet
ClassLoader loader = Sncp.class.getClassLoader(); ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet"; String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet";
try {
return ((Class<T>) Class.forName(newDynName.replace('/', '.'))).newInstance();
} catch (Exception ex) {
}
Method currentUserMethod = null; Method currentUserMethod = null;
try { try {
currentUserMethod = baseServletClass.getDeclaredMethod("currentUser", HttpRequest.class); currentUserMethod = baseServletClass.getDeclaredMethod("currentUser", HttpRequest.class);
@@ -113,7 +152,7 @@ public final class Rest {
final String defmodulename = getWebModuleName(serviceType); final String defmodulename = getWebModuleName(serviceType);
for (char ch : defmodulename.toCharArray()) { for (char ch : defmodulename.toCharArray()) {
if (!((ch >= '0' && ch <= '9') || ch == '$' || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //不能含特殊字符 if (!((ch >= '0' && ch <= '9') || ch == '$' || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //不能含特殊字符
throw new RuntimeException(serviceType.getName() + " has illeal " + RestService.class.getSimpleName() + ".value, only 0-9 a-z A-Z _ $"); throw new RuntimeException(serviceType.getName() + " have illeal " + RestService.class.getSimpleName() + ".value, only 0-9 a-z A-Z _ $");
} }
} }
@@ -122,7 +161,7 @@ public final class Rest {
AsmMethodVisitor mv; AsmMethodVisitor mv;
AnnotationVisitor av0; AnnotationVisitor av0;
Map<String, Object> classMap = new LinkedHashMap<>(); Map<String, Object> classMap = new LinkedHashMap<>();
List<Map<String, Object>> actionMaps = new ArrayList<>(); List<Map<String, Object>> mappingMaps = new ArrayList<>();
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null); cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
{ //RestDynamic { //RestDynamic
@@ -163,6 +202,10 @@ public final class Rest {
fv = cw.visitField(ACC_PRIVATE, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;" + serviceDesc + ">;", null); fv = cw.visitField(ACC_PRIVATE, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;" + serviceDesc + ">;", null);
fv.visitEnd(); fv.visitEnd();
} }
{ //_paramtypes字段 java.lang.reflect.Type[][]
fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null);
fv.visitEnd();
}
{ //构造函数 { //构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)); mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true); //mv.setDebug(true);
@@ -175,7 +218,9 @@ public final class Rest {
final List<MappingEntry> entrys = new ArrayList<>(); final List<MappingEntry> entrys = new ArrayList<>();
final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>(); final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
//获取所有可以转换成WebMapping的方法
int methodidex = 0;
final List<java.lang.reflect.Type[]> paramtypes = new ArrayList<>();
for (final Method method : serviceType.getMethods()) { for (final Method method : serviceType.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue; if (Modifier.isStatic(method.getModifiers())) continue;
Class[] extypes = method.getExceptionTypes(); Class[] extypes = method.getExceptionTypes();
@@ -195,22 +240,28 @@ public final class Rest {
} }
} }
if (ignore) continue; if (ignore) continue;
paramtypes.add(method.getGenericParameterTypes());
if (mappings.length == 0) { //没有Mapping设置一个默认值 if (mappings.length == 0) { //没有Mapping设置一个默认值
MappingEntry entry = new MappingEntry(null, defmodulename, method); MappingEntry entry = new MappingEntry(methodidex, null, defmodulename, method);
if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat"); if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat");
entrys.add(entry); entrys.add(entry);
} else { } else {
for (RestMapping mapping : mappings) { for (RestMapping mapping : mappings) {
MappingEntry entry = new MappingEntry(mapping, defmodulename, method); MappingEntry entry = new MappingEntry(methodidex, mapping, defmodulename, method);
if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat"); if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat");
entrys.add(entry); entrys.add(entry);
} }
} }
methodidex++;
} }
if (entrys.isEmpty()) return null; //没有可WebAction的方法 if (entrys.isEmpty()) return null; //没有可WebMapping的方法
//将每个Service可转换的方法生成HttpServlet对应的WebMapping方法
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(serviceType);
for (final MappingEntry entry : entrys) { for (final MappingEntry entry : entrys) {
final Method method = entry.mappingMethod; final Method method = entry.mappingMethod;
final Class returnType = method.getReturnType(); final Class returnType = method.getReturnType();
final java.lang.reflect.Type returnGenericType = method.getGenericReturnType();
final String methodDesc = Type.getMethodDescriptor(method); final String methodDesc = Type.getMethodDescriptor(method);
final Parameter[] params = method.getParameters(); final Parameter[] params = method.getParameters();
@@ -221,9 +272,9 @@ public final class Rest {
av0 = mv.visitAnnotation(authDesc, true); av0 = mv.visitAnnotation(authDesc, true);
av0.visitEnd(); av0.visitEnd();
} }
if (entry.cachetimeout > 0) { //设置 HttpCacheable if (entry.cacheseconds > 0) { //设置 HttpCacheable
av0 = mv.visitAnnotation(cacheDesc, true); av0 = mv.visitAnnotation(cacheDesc, true);
av0.visit("timeout", entry.cachetimeout); av0.visit("seconds", entry.cacheseconds);
av0.visitEnd(); av0.visitEnd();
} }
@@ -254,14 +305,16 @@ public final class Rest {
final int maxStack = 3 + params.length; final int maxStack = 3 + params.length;
List<int[]> varInsns = new ArrayList<>(); List<int[]> varInsns = new ArrayList<>();
int maxLocals = 4; int maxLocals = 4;
final String jsvar = entry.jsvar.isEmpty() ? null : entry.jsvar;
int argIndex = 0;
List<String> asmParamNames = asmParamMap == null ? null : asmParamMap.get(method.getName() + ":" + Type.getMethodDescriptor(method));
List<Object[]> paramlist = new ArrayList<>(); List<Object[]> paramlist = new ArrayList<>();
for (final Parameter param : params) { //解析方法中的每个参数
for (int i = 0; i < params.length; i++) {
final Parameter param = params[i];
final Class ptype = param.getType(); final Class ptype = param.getType();
String n = null; String n = null;
String comment = ""; String comment = "";
boolean required = true;
int radix = 10; int radix = 10;
RestHeader annhead = param.getAnnotation(RestHeader.class); RestHeader annhead = param.getAnnotation(RestHeader.class);
@@ -297,27 +350,29 @@ public final class Rest {
RestParam annpara = param.getAnnotation(RestParam.class); RestParam annpara = param.getAnnotation(RestParam.class);
if (annpara != null) radix = annpara.radix(); if (annpara != null) radix = annpara.radix();
if (annpara != null) comment = annpara.comment(); if (annpara != null) comment = annpara.comment();
if (annpara != null) required = annpara.required();
if (n == null) n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name(); if (n == null) n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name();
if (n == null && ptype == userType) n = "&"; //用户类型特殊处理 if (n == null && ptype == userType) n = "&"; //用户类型特殊处理
if (n == null && asmParamNames != null && asmParamNames.size() > i) n = asmParamNames.get(i);
if (n == null) { if (n == null) {
if (param.isNamePresent()) { if (param.isNamePresent()) {
n = param.getName(); n = param.getName();
} else if (ptype == Flipper.class) { } else if (ptype == Flipper.class) {
n = "flipper"; n = "flipper";
} else { } else {
n = (++argIndex > 1) ? ("bean" + argIndex) : "bean"; n = ("bean" + i);
} }
} }
if (annhead == null && anncookie == null && annaddr == null if (annhead == null && anncookie == null && annaddr == null
&& (entry.name.startsWith("find") || entry.name.startsWith("delete")) && params.length == 1) { && (entry.name.startsWith("find") || entry.name.startsWith("delete")) && params.length == 1) {
if (ptype.isPrimitive() || ptype == String.class) n = "#"; if (ptype.isPrimitive() || ptype == String.class) n = "#";
} }
paramlist.add(new Object[]{param, n, ptype, radix, comment, annpara, annsid, annaddr, annhead, anncookie}); paramlist.add(new Object[]{param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie});
} }
Map<String, Object> actionMap = new LinkedHashMap<>(); Map<String, Object> mappingMap = new LinkedHashMap<>();
{ { // 设置 Annotation
//设置 WebAction //设置 WebMapping
boolean reqpath = false; boolean reqpath = false;
for (Object[] ps : paramlist) { for (Object[] ps : paramlist) {
if ("#".equals((String) ps[1])) { if ("#".equals((String) ps[1])) {
@@ -325,7 +380,7 @@ public final class Rest {
break; break;
} }
} }
av0 = mv.visitAnnotation(actionDesc, true); av0 = mv.visitAnnotation(mappingDesc, true);
String url = "/" + defmodulename.toLowerCase() + "/" + entry.name + (reqpath ? "/" : ""); String url = "/" + defmodulename.toLowerCase() + "/" + entry.name + (reqpath ? "/" : "");
av0.visit("url", url); av0.visit("url", url);
av0.visit("actionid", entry.actionid); av0.visit("actionid", entry.actionid);
@@ -341,22 +396,22 @@ public final class Rest {
av0.visit("result", grt == returnType ? returnType.getName() : String.valueOf(grt)); av0.visit("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
av0.visitEnd(); av0.visitEnd();
actionMap.put("url", url); mappingMap.put("url", url);
actionMap.put("auth", entry.auth); mappingMap.put("auth", entry.auth);
actionMap.put("cachetimeout", entry.cachetimeout); mappingMap.put("cachetimeout", entry.cacheseconds);
actionMap.put("actionid", entry.actionid); mappingMap.put("actionid", entry.actionid);
actionMap.put("comment", entry.comment); mappingMap.put("comment", entry.comment);
actionMap.put("methods", entry.methods); mappingMap.put("methods", entry.methods);
actionMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt)); mappingMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
} }
{ { // 设置 Annotation
av0 = mv.visitAnnotation(webparamsDesc, true); av0 = mv.visitAnnotation(webparamsDesc, true);
AnnotationVisitor av1 = av0.visitArray("value"); AnnotationVisitor av1 = av0.visitArray("value");
//设置 WebParam //设置 WebParam
for (Object[] ps : paramlist) { //{param, n, ptype, radix, comment, annpara, annsid, annaddr, annhead, anncookie} for (Object[] ps : paramlist) { //{param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie}
final boolean ishead = ((RestHeader) ps[8]) != null; //是否取getHeader 而不是 getParameter final boolean ishead = ((RestHeader) ps[9]) != null; //是否取getHeader 而不是 getParameter
final boolean iscookie = ((RestCookie) ps[9]) != null; //是否取getCookie final boolean iscookie = ((RestCookie) ps[10]) != null; //是否取getCookie
AnnotationVisitor av2 = av1.visitAnnotation(null, webparamDesc); AnnotationVisitor av2 = av1.visitAnnotation(null, webparamDesc);
av2.visit("name", (String) ps[1]); av2.visit("name", (String) ps[1]);
@@ -365,30 +420,51 @@ public final class Rest {
av2.visitEnum("src", sourcetypeDesc, ishead ? HttpBaseServlet.ParamSourceType.HEADER.name() av2.visitEnum("src", sourcetypeDesc, ishead ? HttpBaseServlet.ParamSourceType.HEADER.name()
: (iscookie ? HttpBaseServlet.ParamSourceType.COOKIE.name() : HttpBaseServlet.ParamSourceType.PARAMETER.name())); : (iscookie ? HttpBaseServlet.ParamSourceType.COOKIE.name() : HttpBaseServlet.ParamSourceType.PARAMETER.name()));
av2.visit("comment", (String) ps[4]); av2.visit("comment", (String) ps[4]);
av2.visit("required", (Boolean) ps[5]);
av2.visitEnd(); av2.visitEnd();
} }
av1.visitEnd(); av1.visitEnd();
av0.visitEnd(); av0.visitEnd();
} }
List<Map<String, Object>> paramMaps = new ArrayList<>(); List<Map<String, Object>> paramMaps = new ArrayList<>();
//获取每个参数的值
boolean hasAsyncHandler = false;
for (Object[] ps : paramlist) { for (Object[] ps : paramlist) {
Map<String, Object> paramMap = new LinkedHashMap<>(); Map<String, Object> paramMap = new LinkedHashMap<>();
final Parameter param = (Parameter) ps[0]; //参数类型
String pname = (String) ps[1]; //参数名 String pname = (String) ps[1]; //参数名
Class ptype = (Class) ps[2]; Class ptype = (Class) ps[2]; //参数类型
int radix = (Integer) ps[3]; int radix = (Integer) ps[3];
String comment = (String) ps[4]; String comment = (String) ps[4];
RestParam annpara = (RestParam) ps[5]; boolean required = (Boolean) ps[5];
RestSessionid annsid = (RestSessionid) ps[6]; RestParam annpara = (RestParam) ps[6];
RestAddress annaddr = (RestAddress) ps[7]; RestSessionid annsid = (RestSessionid) ps[7];
RestHeader annhead = (RestHeader) ps[8]; RestAddress annaddr = (RestAddress) ps[8];
RestCookie anncookie = (RestCookie) ps[9]; RestHeader annhead = (RestHeader) ps[9];
RestCookie anncookie = (RestCookie) ps[10];
final boolean ishead = annhead != null; //是否取getHeader 而不是 getParameter final boolean ishead = annhead != null; //是否取getHeader 而不是 getParameter
final boolean iscookie = anncookie != null; //是否取getCookie final boolean iscookie = anncookie != null; //是否取getCookie
paramMap.put("name", pname); paramMap.put("name", pname);
paramMap.put("type", ptype.getName()); paramMap.put("type", ptype.getName());
if (annsid != null) { //HttpRequest.getSessionid(true|false) if (AsyncHandler.class.isAssignableFrom(ptype)) { //HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class)
if (ptype == AsyncHandler.class) {
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "()Lorg/redkale/util/AsyncHandler;", false);
mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals});
} else {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype)));
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "createAsyncHandler", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/Class;)Lorg/redkale/util/AsyncHandler;", false);
mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals});
}
hasAsyncHandler = true;
} else if (annsid != null) { //HttpRequest.getSessionid(true|false)
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0); mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0);
mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false);
@@ -630,7 +706,31 @@ public final class Rest {
varInsns.add(new int[]{ALOAD, maxLocals}); varInsns.add(new int[]{ALOAD, maxLocals});
} else { //其他Json对象 } else { //其他Json对象
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype))); if (param.getType() == param.getParameterizedType()) {
mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype)));
} else {
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;");
if (entry.methodidx <= 5) { //方法下标
mv.visitInsn(ICONST_0 + entry.methodidx);
} else {
mv.visitIntInsn(BIPUSH, entry.methodidx);
}
mv.visitInsn(AALOAD);
int paramidx = 0;
for (int i = 0; i < params.length; i++) {
if (params[i] == param) {
paramidx = i;
break;
}
}
if (paramidx <= 5) { //参数下标
mv.visitInsn(ICONST_0 + paramidx);
} else {
mv.visitIntInsn(BIPUSH, paramidx);
}
mv.visitInsn(AALOAD);
}
mv.visitLdcInsn(pname); mv.visitLdcInsn(pname);
mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "getJsonHeader" : "getJsonParameter", "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", false); mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "getJsonHeader" : "getJsonParameter", "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
@@ -720,227 +820,140 @@ public final class Rest {
mv.visitVarInsn(ins[0], ins[1]); mv.visitVarInsn(ins[0], ins[1]);
} }
mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false); mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false);
if (returnType == void.class) { if (hasAsyncHandler) {
mv.visitInsn(RETURN);
} else if (returnType == void.class) {
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false); mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
} else if (returnType == boolean.class) { } else if (returnType == boolean.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ILOAD, maxLocals);
mv.visitVarInsn(ILOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == byte.class) { } else if (returnType == byte.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ILOAD, maxLocals);
mv.visitVarInsn(ILOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == short.class) { } else if (returnType == short.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ILOAD, maxLocals);
mv.visitVarInsn(ILOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == char.class) { } else if (returnType == char.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ILOAD, maxLocals);
mv.visitVarInsn(ILOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == int.class) { } else if (returnType == int.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ILOAD, maxLocals);
mv.visitVarInsn(ILOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == float.class) { } else if (returnType == float.class) {
mv.visitVarInsn(FSTORE, maxLocals); mv.visitVarInsn(FSTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(FLOAD, maxLocals);
mv.visitVarInsn(FLOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(FLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == long.class) { } else if (returnType == long.class) {
mv.visitVarInsn(LSTORE, maxLocals); mv.visitVarInsn(LSTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(LLOAD, maxLocals);
mv.visitVarInsn(LLOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(LLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals += 2; maxLocals += 2;
} else if (returnType == double.class) { } else if (returnType == double.class) {
mv.visitVarInsn(DSTORE, maxLocals); mv.visitVarInsn(DSTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(DLOAD, maxLocals);
mv.visitVarInsn(DLOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(DLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals += 2; maxLocals += 2;
} else if (returnType == String.class) { } else if (returnType == String.class) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, maxLocals);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == File.class) { } else if (returnType == File.class) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, maxLocals);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false);
} else {
throw new RuntimeException(method + " cannot set return Type (java.io.File) to jsvar");
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (RetResult.class.isAssignableFrom(returnType)) { } else if (RetResult.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, maxLocals);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (RestOutput.class.isAssignableFrom(returnType)) { } else if (RestOutput.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + restoutputDesc + ")V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + restoutputDesc + ")V", false);
} else {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJsResult", "(" + respDesc + "Ljava/lang/String;" + restoutputDesc + ")V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面 } else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, maxLocals);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitInsn(RETURN);
} else { maxLocals++;
mv.visitVarInsn(ALOAD, 2); } else if (futureRestOutputType == returnGenericType) {
mv.visitLdcInsn(jsvar); mv.visitVarInsn(ASTORE, maxLocals);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false); mv.visitVarInsn(ALOAD, 2);
} mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + futureDesc + ")V", false);
mv.visitInsn(RETURN);
maxLocals++;
} else if (CompletableFuture.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals);
mv.visitVarInsn(ALOAD, 2);//response
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + futureDesc + ")V", false);
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else { } else {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) { mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, maxLocals);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(Ljava/lang/Object;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(Ljava/lang/Object;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} }
mv.visitMaxs(maxStack, maxLocals); mv.visitMaxs(maxStack, maxLocals);
actionMap.put("params", paramMaps); mappingMap.put("params", paramMaps);
actionMaps.add(actionMap); mappingMaps.add(mappingMap);
} // end for each } // end for each
for (String attrname : restAttributes.keySet()) { for (String attrname : restAttributes.keySet()) {
@@ -948,7 +961,7 @@ public final class Rest {
fv.visitEnd(); fv.visitEnd();
} }
classMap.put("actions", actionMaps); classMap.put("mappings", mappingMaps);
{ //toString函数 { //toString函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
@@ -973,6 +986,12 @@ public final class Rest {
attrField.setAccessible(true); attrField.setAccessible(true);
attrField.set(obj, en.getValue()); attrField.set(obj, en.getValue());
} }
Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME);
typesfield.setAccessible(true);
java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramtypes.size()][];
paramtypeArray = paramtypes.toArray(paramtypeArray);
typesfield.set(obj, paramtypeArray);
return obj; return obj;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@@ -1004,8 +1023,9 @@ public final class Rest {
} }
} }
public MappingEntry(RestMapping mapping, final String defmodulename, Method method) { public MappingEntry(int methodidx, RestMapping mapping, final String defmodulename, Method method) {
if (mapping == null) mapping = DEFAULT__MAPPING; if (mapping == null) mapping = DEFAULT__MAPPING;
this.methodidx = methodidx;
this.ignore = mapping.ignore(); this.ignore = mapping.ignore();
String n = mapping.name().toLowerCase(); String n = mapping.name().toLowerCase();
if (n.isEmpty()) n = method.getName().toLowerCase().replace(defmodulename.toLowerCase(), ""); if (n.isEmpty()) n = method.getName().toLowerCase().replace(defmodulename.toLowerCase(), "");
@@ -1014,12 +1034,12 @@ public final class Rest {
this.methods = mapping.methods(); this.methods = mapping.methods();
this.auth = mapping.auth(); this.auth = mapping.auth();
this.actionid = mapping.actionid(); this.actionid = mapping.actionid();
this.cachetimeout = mapping.cachetimeout(); this.cacheseconds = mapping.cacheseconds();
//this.contentType = mapping.contentType();
this.comment = mapping.comment(); this.comment = mapping.comment();
this.jsvar = mapping.jsvar();
} }
public final int methodidx; // _paramtypes 的下标从0开始
public final Method mappingMethod; public final Method mappingMethod;
public final boolean ignore; public final boolean ignore;
@@ -1034,10 +1054,7 @@ public final class Rest {
public final int actionid; public final int actionid;
public final int cachetimeout; public final int cacheseconds;
//public final String contentType;
public final String jsvar;
@RestMapping() @RestMapping()
void mapping() { //用于获取Mapping 默认值 void mapping() { //用于获取Mapping 默认值

View File

@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestCookie { public @interface RestCookie {
String name(); //cookie名 /**
* cookie名
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 /**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
String comment() default ""; //备注描述 /**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestHeader { public @interface RestHeader {
String name(); //参数名 /**
* Header参数名
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 /**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
String comment() default ""; //备注描述 /**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -6,6 +6,11 @@
package org.redkale.net.http; package org.redkale.net.http;
import java.io.*; import java.io.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.util.*;
/** /**
* *
@@ -18,27 +23,163 @@ public abstract class RestHttpServlet<T> extends HttpBaseServlet {
protected abstract T currentUser(HttpRequest req) throws IOException; protected abstract T currentUser(HttpRequest req) throws IOException;
protected void finishJson(final HttpResponse response, CompletableFuture<RestOutput> future) throws IOException {
future.whenComplete((output, e) -> {
if (e != null) {
response.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + response.getRequest(), e);
response.finish(500, null);
return;
}
try {
finishJson(response, output);
} catch (IOException ioe) {
response.getContext().getLogger().log(Level.WARNING, "Servlet finish RestOutput occur, forece to close channel. request = " + response.getRequest(), ioe);
response.finish(500, null);
}
});
}
protected void finishJson(final HttpResponse response, RestOutput output) throws IOException { protected void finishJson(final HttpResponse response, RestOutput output) throws IOException {
if (output == null) { if (output == null) {
response.finishJson(output); response.finishJson(output);
return; return;
} }
if (output.getContentType() != null) response.setContentType(output.getContentType());
response.addHeader(output.getHeaders()); response.addHeader(output.getHeaders());
response.addCookie(output.getCookies()); response.addCookie(output.getCookies());
response.setStatus(output.getStatus() < 1 ? 200 : output.getStatus());
if (output.getResult() instanceof File) { if (output.getResult() instanceof File) {
response.finish((File) output.getResult()); response.finish((File) output.getResult());
} else if (output.getResult() instanceof String) {
response.finish((String) output.getResult());
} else if (output.getResult() == null) {
response.finish(output.getMessage());
} else { } else {
response.finishJson(output.getResult()); response.finishJson(output.getResult());
} }
} }
protected void finishJsResult(final HttpResponse response, final String var, RestOutput output) throws IOException { /**
if (output != null) { * 创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出 <br>
response.addHeader(output.getHeaders()); *
response.addCookie(output.getCookies()); * 传入的AsyncHandler子类必须是public且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
*
* @param <H> AsyncHandler泛型
* @param response HttpResponse
* @param handlerClass Class
*
* @return AsyncHandler
*/
protected final <H extends AsyncHandler> H createAsyncHandler(HttpResponse response, final Class<H> handlerClass) {
if (handlerClass == null || handlerClass == AsyncHandler.class) return (H) response.createAsyncHandler();
Creator<H> creator = creators.get(handlerClass);
if (creator == null) {
creator = createCreator(handlerClass);
creators.put(handlerClass, creator);
} }
response.finishJsResult(var, output == null ? null : output.getResult()); return (H) creator.create(response.createAsyncHandler());
} }
private static final ConcurrentHashMap<Class, Creator> creators = new ConcurrentHashMap<>();
private static <H extends AsyncHandler> Creator<H> createCreator(Class<H> handlerClass) {
//生成规则与SncpAsyncHandler.Factory 很类似
//-------------------------------------------------------------
final boolean handlerinterface = handlerClass.isInterface();
final String handlerClassName = handlerClass.getName().replace('.', '/');
final String handlerName = AsyncHandler.class.getName().replace('.', '/');
final String handlerDesc = Type.getDescriptor(AsyncHandler.class);
final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + AsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
AsmMethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName});
{ //handler 属性
fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null);
fv.visitEnd();
}
{//构造方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + handlerDesc + ")V", null, null));
//mv.setDebug(true);
{
av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "handler");
av1.visitEnd();
}
av0.visitEnd();
}
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
Class returnType = method.getReturnType();
if (returnType == void.class) {
mv.visitInsn(RETURN);
mv.visitMaxs(0, 1);
} else if (returnType.isPrimitive()) {
mv.visitInsn(ICONST_0);
if (returnType == long.class) {
mv.visitInsn(LRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == float.class) {
mv.visitInsn(FRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == double.class) {
mv.visitInsn(DRETURN);
mv.visitMaxs(2, 1);
} else {
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
}
} else {
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
}
mv.visitEnd();
}
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Class<AsyncHandler> newHandlerClazz = (Class<AsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
return (Creator<H>) Creator.create(newHandlerClazz);
}
} }

View File

@@ -10,8 +10,8 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*; import static java.lang.annotation.RetentionPolicy.*;
/** /**
* 只能依附在Service实现类的public方法上 * 只能依附在Service实现类的public方法上 <br>
* value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService的默认路径为/hello)。 * value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService的默认路径为/hello)。 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -24,26 +24,54 @@ import static java.lang.annotation.RetentionPolicy.*;
@Repeatable(RestMappings.class) @Repeatable(RestMappings.class)
public @interface RestMapping { public @interface RestMapping {
boolean ignore() default false; //是否屏蔽该方法的转换 /**
* 是否屏蔽该方法的转换
*
* @return boolean
*/
boolean ignore() default false;
/** /**
* 请求的方法名, 不能含特殊字符 * 请求的方法名, 不能含特殊字符
* 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前) * 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX、existsXXX且XXXService为Service的类名将只截取XXX之前)
* *
* @return name * @return String
*/ */
String name() default ""; String name() default "";
String comment() default ""; //备注描述, 对应&#64;WebAction.comment /**
* 备注描述, 对应&#64;WebMapping.comment
*
* @return String
*/
String comment() default "";
boolean auth() default false; //是否鉴权,默认不鉴权, 对应&#64;AuthIgnore /**
* 是否鉴权,默认不鉴权, 对应&#64;AuthIgnore
*
* @return boolean
*/
boolean auth() default false;
int actionid() default 0; //操作ID值鉴权时用到, 对应&#64;WebAction.actionid /**
* 操作ID值鉴权时用到, 对应&#64;WebMapping.actionid
*
* @return int
*/
int actionid() default 0;
int cachetimeout() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpCacheable.timeout /**
* 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpCacheable.seconds
*
* @return int
*/
int cacheseconds() default 0;
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebAction.methods /**
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebMapping.methods
*
* @return String[]
*/
String[] methods() default {};
//String contentType() default ""; //设置Response的ContentType 默认值为 text/plain; charset=utf-8
String jsvar() default ""; //以application/javascript输出对象是指明js的对象名该值存在时则忽略contentType()的值
} }

View File

@@ -23,8 +23,14 @@ public class RestOutput<T> {
private List<HttpCookie> cookies; private List<HttpCookie> cookies;
private String contentType;
private T result; private T result;
private int status = 0; //不设置则为 200
private String message;
public RestOutput() { public RestOutput() {
} }
@@ -32,14 +38,16 @@ public class RestOutput<T> {
this.result = result; this.result = result;
} }
public void addHeader(String name, Serializable value) { public RestOutput<T> addHeader(String name, Serializable value) {
if (this.headers == null) this.headers = new HashMap<>(); if (this.headers == null) this.headers = new HashMap<>();
this.headers.put(name, String.valueOf(value)); this.headers.put(name, String.valueOf(value));
return this;
} }
public void addCookie(HttpCookie cookie) { public RestOutput<T> addCookie(HttpCookie cookie) {
if (this.cookies == null) this.cookies = new ArrayList<>(); if (this.cookies == null) this.cookies = new ArrayList<>();
this.cookies.add(cookie); this.cookies.add(cookie);
return this;
} }
public Map<String, String> getHeaders() { public Map<String, String> getHeaders() {
@@ -58,6 +66,14 @@ public class RestOutput<T> {
this.cookies = cookies; this.cookies = cookies;
} }
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public T getResult() { public T getResult() {
return result; return result;
} }
@@ -66,4 +82,20 @@ public class RestOutput<T> {
this.result = result; this.result = result;
} }
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
} }

View File

@@ -10,9 +10,11 @@ import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 只能依附在Service类的方法的参数上, name值不能是'&#38;' *
* name='#'表示截取uri最后一段 * 依附在RestService类的方法的参数上 <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 * name='&#38;' 表示当前用户 <br>
* name='#'表示截取uri最后一段 <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -24,9 +26,36 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestParam { public @interface RestParam {
String name(); //参数名 //name='&'表示当前用户;
/**
* 参数名 <br>
* name='&#38;'表示当前用户; <br>
* name='#'表示截取uri最后一段; <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* 若方法名以find、delete开头且方法的参数只有一个且参数类型是基本数据类型或String则默认值为"#" <br>
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 /**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
String comment() default ""; //备注描述 /**
* 参数是否必传
*
* @return boolean
*/
boolean required() default true;
/**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -1,26 +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.http;
import java.lang.annotation.*;
/**
* 功能同JSR 315 (java-servlet 3.0) 规范中的 @WebInitParam
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebInitParam {
String name();
String value();
String description() default "";
}

View File

@@ -21,15 +21,38 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface WebServlet { public @interface WebServlet {
/**
* HttpServlet资源名
*
* @return String
*/
String name() default ""; String name() default "";
/**
* 是否自动添加url前缀, 对应application.xml中servlets节点的path属性
*
* @return boolean
*/
boolean repair() default true; boolean repair() default true;
/**
* url匹配规则
*
* @return String[]
*/
String[] value() default {}; String[] value() default {};
/**
* 模块ID一个HttpServlet尽量只有提供一个模块的服务
*
* @return int
*/
int moduleid() default 0; int moduleid() default 0;
WebInitParam[] initParams() default {}; /**
* 备注描述
String comment() default ""; //备注描述 *
* @return String
*/
String comment() default "";
} }

View File

@@ -10,7 +10,9 @@ import java.io.*;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.util.Comment;
/** /**
* <blockquote><pre> * <blockquote><pre>
@@ -22,15 +24,13 @@ import org.redkale.net.*;
* 1.3 onConnected WebSocket成功连接后在准备接收数据前回调此方法。 * 1.3 onConnected WebSocket成功连接后在准备接收数据前回调此方法。
* 1.4 onMessage/onFragment+ WebSocket接收到消息后回调此消息类方法。 * 1.4 onMessage/onFragment+ WebSocket接收到消息后回调此消息类方法。
* 1.5 onClose WebSocket被关闭后回调此方法。 * 1.5 onClose WebSocket被关闭后回调此方法。
* * 普通模式下 以上方法都应该被重载。
* 此模式下 以上方法都应该被重载。
* *
* 2) 原始二进制模式: 此模式有别于HTML5规范可以视为原始的TCP连接。通常用于音频视频通讯场景。其流程顺序如下: * 2) 原始二进制模式: 此模式有别于HTML5规范可以视为原始的TCP连接。通常用于音频视频通讯场景。其流程顺序如下:
* 2.1 onOpen 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。 * 2.1 onOpen 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。
* 2.2 createGroupid 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。 * 2.2 createGroupid 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。
* 2.3 onRead WebSocket成功连接后回调此方法 由此方法处理原始的TCP连接 同时业务代码去控制WebSocket的关闭。 * 2.3 onRead WebSocket成功连接后回调此方法 由此方法处理原始的TCP连接 需要业务代码去控制WebSocket的关闭。
* * 二进制模式下 以上方法都应该被重载。
* 此模式下 以上方法都应该被重载。
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -39,24 +39,28 @@ import org.redkale.net.*;
*/ */
public abstract class WebSocket { public abstract class WebSocket {
//消息不合法 @Comment("消息不合法")
public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2 public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2
//ws已经关闭 @Comment("WebSocket已经关闭")
public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4 public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4
//socket的buffer不合法 @Comment("Socket的buffer不合法")
public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8 public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8
//ws发送消息异常 @Comment("WebSocket发送消息异常")
public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16 public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16
@Comment("WebSocketEngine实例不存在")
public static final int RETCODE_ENGINE_NULL = 1 << 5; //32 public static final int RETCODE_ENGINE_NULL = 1 << 5; //32
@Comment("WebSocketNode实例不存在")
public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64 public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64
@Comment("WebSocket组为空, 表示无WebSocket连接")
public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128 public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128
@Comment("WebSocket已离线")
public static final int RETCODE_WSOFFLINE = 1 << 8; //256 public static final int RETCODE_WSOFFLINE = 1 << 8; //256
WebSocketRunner _runner; //不可能为空 WebSocketRunner _runner; //不可能为空
@@ -73,6 +77,8 @@ public abstract class WebSocket {
String _remoteAddr;//不可能为空 String _remoteAddr;//不可能为空
JsonConvert _jsonConvert; //不可能为空
private final long createtime = System.currentTimeMillis(); private final long createtime = System.currentTimeMillis();
private final Map<String, Object> attributes = new ConcurrentHashMap<>(); private final Map<String, Object> attributes = new ConcurrentHashMap<>();
@@ -82,9 +88,10 @@ public abstract class WebSocket {
//---------------------------------------------------------------- //----------------------------------------------------------------
/** /**
* 发送消息体, 包含二进制/文本 * 给自身发送消息体, 包含二进制/文本
* *
* @param packet WebSocketPacket * @param packet WebSocketPacket
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(WebSocketPacket packet) { public final int send(WebSocketPacket packet) {
@@ -95,9 +102,10 @@ public abstract class WebSocket {
} }
/** /**
* 发送单一的文本消息 * 给自身发送单一的文本消息
* *
* @param text 不可为空 * @param text 不可为空
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(String text) { public final int send(String text) {
@@ -105,10 +113,11 @@ public abstract class WebSocket {
} }
/** /**
* 发送文本消息 * 给自身发送文本消息
* *
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(String text, boolean last) { public final int send(String text, boolean last) {
@@ -133,9 +142,10 @@ public abstract class WebSocket {
} }
/** /**
* 发送单一的二进制消息 * 给自身发送单一的二进制消息
* *
* @param data byte[] * @param data byte[]
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(byte[] data) { public final int send(byte[] data) {
@@ -143,10 +153,11 @@ public abstract class WebSocket {
} }
/** /**
* 发送二进制消息 * 给自身发送二进制消息
* *
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(byte[] data, boolean last) { public final int send(byte[] data, boolean last) {
@@ -154,14 +165,30 @@ public abstract class WebSocket {
} }
/** /**
* 发送消息, 消息类型是String或byte[] * 给自身发送消息, 消息类型是String或byte[]或可JSON化对象
*
* @param message 不可为空, 只能是String或byte[]或可JSON化对象
* *
* @param message 不可为空, 只能是String或者byte[]
* @param last 是否最后一条
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(Serializable message, boolean last) { public final int send(Object message) {
return send(new WebSocketPacket(message, last)); return send(message, true);
}
/**
* 给自身发送消息, 消息类型是String或byte[]或可JSON化对象
*
* @param message 不可为空, 只能是String或byte[]或可JSON化对象
* @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码
*/
public final int send(Object message, boolean last) {
if (message == null || message instanceof CharSequence || message instanceof byte[]) {
return send(new WebSocketPacket((Serializable) message, last));
} else {
return send(new WebSocketPacket(_jsonConvert.convertTo(message), last));
}
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
@@ -170,6 +197,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, String text) { public final int sendEachMessage(Serializable groupid, String text) {
@@ -181,10 +209,23 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, byte[] data) { public final int sendEachMessage(Serializable groupid, byte[] data) {
return WebSocket.this.sendEachMessage(groupid, data, true); return sendEachMessage(groupid, data, true);
}
/**
* 给指定groupid的WebSocketGroup下所有WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendEachMessage(Serializable groupid, Object message) {
return sendEachMessage(groupid, message, true);
} }
/** /**
@@ -193,6 +234,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, String text, boolean last) { public final int sendEachMessage(Serializable groupid, String text, boolean last) {
@@ -205,17 +247,32 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) { public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) {
return sendMessage(groupid, false, data, last); return sendMessage(groupid, false, data, last);
} }
/**
* 给指定groupid的WebSocketGroup下所有WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
* @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendEachMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, false, message, last);
}
/** /**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息 * 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息
* *
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, String text) { public final int sendRecentMessage(Serializable groupid, String text) {
@@ -227,18 +284,32 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, byte[] data) { public final int sendRecentMessage(Serializable groupid, byte[] data) {
return sendRecentMessage(groupid, data, true); return sendRecentMessage(groupid, data, true);
} }
/**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendRecentMessage(Serializable groupid, Object message) {
return sendMessage(groupid, true, message, true);
}
/** /**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息 * 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息
* *
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, String text, boolean last) { public final int sendRecentMessage(Serializable groupid, String text, boolean last) {
@@ -251,12 +322,26 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) { public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) {
return sendMessage(groupid, true, data, last); return sendMessage(groupid, true, data, last);
} }
/**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
* @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendRecentMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, true, message, last);
}
private int sendMessage(Serializable groupid, boolean recent, String text, boolean last) { private int sendMessage(Serializable groupid, boolean recent, String text, boolean last) {
if (_engine.node == null) return RETCODE_NODESERVICE_NULL; if (_engine.node == null) return RETCODE_NODESERVICE_NULL;
int rs = _engine.node.sendMessage(groupid, recent, text, last); int rs = _engine.node.sendMessage(groupid, recent, text, last);
@@ -271,10 +356,18 @@ public abstract class WebSocket {
return rs; return rs;
} }
private int sendMessage(Serializable groupid, boolean recent, Object message, boolean last) {
if (_engine.node == null) return RETCODE_NODESERVICE_NULL;
int rs = _engine.node.sendMessage(groupid, recent, message, last);
if (_engine.finest) _engine.logger.finest("wsgroupid:" + groupid + " " + (recent ? "recent " : "") + "send websocket result is " + rs + " on " + this + " by message(" + _jsonConvert.convertTo(message) + ")");
return rs;
}
/** /**
* 获取在线用户的节点地址列表 * 获取指定groupid在线用户的节点地址列表
* *
* @param groupid groupid * @param groupid groupid
*
* @return 地址列表 * @return 地址列表
*/ */
protected final Collection<InetSocketAddress> getOnlineNodes(Serializable groupid) { protected final Collection<InetSocketAddress> getOnlineNodes(Serializable groupid) {
@@ -282,9 +375,10 @@ public abstract class WebSocket {
} }
/** /**
* 获取在线用户的详细连接信息 * 获取指定groupid在线用户的详细连接信息
* *
* @param groupid groupid * @param groupid groupid
*
* @return 地址集合 * @return 地址集合
*/ */
protected final Map<InetSocketAddress, List<String>> getOnlineRemoteAddress(Serializable groupid) { protected final Map<InetSocketAddress, List<String>> getOnlineRemoteAddress(Serializable groupid) {
@@ -296,6 +390,7 @@ public abstract class WebSocket {
* *
* @param <T> 属性值的类型 * @param <T> 属性值的类型
* @param name 属性名 * @param name 属性名
*
* @return 属性值 * @return 属性值
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -308,6 +403,7 @@ public abstract class WebSocket {
* *
* @param <T> 属性值的类型 * @param <T> 属性值的类型
* @param name 属性名 * @param name 属性名
*
* @return 属性值 * @return 属性值
*/ */
public final <T> T removeAttribute(String name) { public final <T> T removeAttribute(String name) {
@@ -374,6 +470,7 @@ public abstract class WebSocket {
* 获取指定groupid的WebSocketGroup, 没有返回null * 获取指定groupid的WebSocketGroup, 没有返回null
* *
* @param groupid groupid * @param groupid groupid
*
* @return WebSocketGroup * @return WebSocketGroup
*/ */
protected final WebSocketGroup getWebSocketGroup(Serializable groupid) { protected final WebSocketGroup getWebSocketGroup(Serializable groupid) {
@@ -394,6 +491,7 @@ public abstract class WebSocket {
* 返回sessionid, null表示连接不合法或异常,默认实现是request.getSessionid(false),通常需要重写该方法 * 返回sessionid, null表示连接不合法或异常,默认实现是request.getSessionid(false),通常需要重写该方法
* *
* @param request HttpRequest * @param request HttpRequest
*
* @return sessionid * @return sessionid
*/ */
public Serializable onOpen(final HttpRequest request) { public Serializable onOpen(final HttpRequest request) {

View File

@@ -15,7 +15,9 @@ import org.redkale.util.*;
/** /**
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
*/ */
public final class WebSocketEngine { public final class WebSocketEngine {

View File

@@ -83,7 +83,7 @@ public final class WebSocketGroup {
attributes.put(name, value); attributes.put(name, value);
} }
public final int send(boolean recent, Serializable message, boolean last) { public final int send(boolean recent, Object message, boolean last) {
if (recent) { if (recent) {
return recentWebSocket.send(message, last); return recentWebSocket.send(message, last);
} else { } else {
@@ -91,7 +91,7 @@ public final class WebSocketGroup {
} }
} }
public final int sendEach(Serializable message) { public final int sendEach(Object message) {
return sendEach(message, true); return sendEach(message, true);
} }
@@ -111,7 +111,7 @@ public final class WebSocketGroup {
return rs; return rs;
} }
public final int sendRecent(Serializable message) { public final int sendRecent(Object message) {
return sendRecent(message, true); return sendRecent(message, true);
} }
@@ -119,7 +119,10 @@ public final class WebSocketGroup {
return recentWebSocket.send(packet); return recentWebSocket.send(packet);
} }
public final int sendEach(Serializable message, boolean last) { public final int sendEach(Object message, boolean last) {
if (message != null && !(message instanceof byte[]) && !(message instanceof CharSequence)) {
message = recentWebSocket._jsonConvert.convertTo(message);
}
int rs = 0; int rs = 0;
for (WebSocket s : list) { for (WebSocket s : list) {
rs |= s.send(message, last); rs |= s.send(message, last);
@@ -127,7 +130,7 @@ public final class WebSocketGroup {
return rs; return rs;
} }
public final int sendRecent(Serializable message, boolean last) { public final int sendRecent(Object message, boolean last) {
return recentWebSocket.send(message, last); return recentWebSocket.send(message, last);
} }

View File

@@ -38,7 +38,7 @@ public abstract class WebSocketNode {
//存放所有用户分布在节点上的队列信息,Set<InetSocketAddress> 为 sncpnode 的集合 //存放所有用户分布在节点上的队列信息,Set<InetSocketAddress> 为 sncpnode 的集合
@Resource(name = "$") @Resource(name = "$")
protected CacheSource<Serializable, InetSocketAddress> source; protected CacheSource<Serializable, InetSocketAddress> sncpNodes;
//存放本地节点上所有在线用户的队列信息,Set<String> 为 engineid 的集合 //存放本地节点上所有在线用户的队列信息,Set<String> 为 engineid 的集合
protected final ConcurrentHashMap<Serializable, Set<String>> localNodes = new ConcurrentHashMap(); protected final ConcurrentHashMap<Serializable, Set<String>> localNodes = new ConcurrentHashMap();
@@ -60,7 +60,7 @@ public abstract class WebSocketNode {
protected abstract List<String> getOnlineRemoteAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid); protected abstract List<String> getOnlineRemoteAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid);
protected abstract int sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid, boolean recent, Serializable message, boolean last); protected abstract int sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid, boolean recent, Object message, boolean last);
protected abstract void connect(Serializable groupid, InetSocketAddress addr); protected abstract void connect(Serializable groupid, InetSocketAddress addr);
@@ -85,7 +85,7 @@ public abstract class WebSocketNode {
* @return 地址列表 * @return 地址列表
*/ */
public Collection<InetSocketAddress> getOnlineNodes(final Serializable groupid) { public Collection<InetSocketAddress> getOnlineNodes(final Serializable groupid) {
return source == null ? null : source.getCollection(groupid); return sncpNodes == null ? null : sncpNodes.getCollection(groupid);
} }
/** /**
@@ -133,7 +133,7 @@ public abstract class WebSocketNode {
engines.put(engine.getEngineid(), engine); engines.put(engine.getEngineid(), engine);
} }
public final int sendMessage(Serializable groupid, boolean recent, Serializable message, boolean last) { public final int sendMessage(Serializable groupid, boolean recent, Object message, boolean last) {
final Set<String> engineids = localNodes.get(groupid); final Set<String> engineids = localNodes.get(groupid);
if (finest) logger.finest("websocket want send message {groupid:" + groupid + ", content:'" + message + "'} from locale node to " + engineids); if (finest) logger.finest("websocket want send message {groupid:" + groupid + ", content:'" + message + "'} from locale node to " + engineids);
int rscode = RETCODE_GROUP_EMPTY; int rscode = RETCODE_GROUP_EMPTY;
@@ -152,7 +152,7 @@ public abstract class WebSocketNode {
} }
} }
} }
if ((recent && rscode == 0) || remoteNode == null || source == null) { if ((recent && rscode == 0) || remoteNode == null || sncpNodes == null) {
if (finest) { if (finest) {
if ((recent && rscode == 0)) { if ((recent && rscode == 0)) {
logger.finest("websocket want send recent message success"); logger.finest("websocket want send recent message success");
@@ -163,7 +163,7 @@ public abstract class WebSocketNode {
return rscode; return rscode;
} }
//-----------------------发送远程的----------------------------- //-----------------------发送远程的-----------------------------
Collection<InetSocketAddress> addrs = source.getCollection(groupid); Collection<InetSocketAddress> addrs = sncpNodes.getCollection(groupid);
if (finest) logger.finest("websocket found groupid:" + groupid + " on " + addrs); if (finest) logger.finest("websocket found groupid:" + groupid + " on " + addrs);
if (addrs != null && !addrs.isEmpty()) { //对方连接在远程节点(包含本地节点)所以正常情况下addrs不会为空。 if (addrs != null && !addrs.isEmpty()) { //对方连接在远程节点(包含本地节点)所以正常情况下addrs不会为空。
if (recent) { if (recent) {
@@ -187,44 +187,44 @@ public abstract class WebSocketNode {
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
public final int sendEachMessage(Serializable groupid, String text) { public final int sendEachMessage(Serializable groupid, String text) {
return sendMessage(groupid, false, text); return sendMessage(groupid, false, (Object) text, true);
} }
public final int sendEachMessage(Serializable groupid, String text, boolean last) { public final int sendEachMessage(Serializable groupid, String text, boolean last) {
return sendMessage(groupid, false, text, last); return sendMessage(groupid, false, (Object) text, last);
} }
public final int sendRecentMessage(Serializable groupid, String text) { public final int sendRecentMessage(Serializable groupid, String text) {
return sendMessage(groupid, true, text); return sendMessage(groupid, true, (Object) text, true);
} }
public final int sendRecentMessage(Serializable groupid, String text, boolean last) { public final int sendRecentMessage(Serializable groupid, String text, boolean last) {
return sendMessage(groupid, true, text, last); return sendMessage(groupid, true, (Object) text, last);
} }
public final int sendMessage(Serializable groupid, boolean recent, String text) { public final int sendMessage(Serializable groupid, boolean recent, String text) {
return sendMessage(groupid, recent, text, true); return sendMessage(groupid, recent, (Object) text, true);
} }
public final int sendMessage(Serializable groupid, boolean recent, String text, boolean last) { public final int sendMessage(Serializable groupid, boolean recent, String text, boolean last) {
return sendMessage(groupid, recent, (Serializable) text, last); return sendMessage(groupid, recent, (Object) text, last);
} }
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
public final int sendEachMessage(Serializable groupid, byte[] data) { public final int sendEachMessage(Serializable groupid, byte[] data) {
return sendMessage(groupid, false, data); return sendMessage(groupid, false, (Object) data, true);
} }
public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) { public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) {
return sendMessage(groupid, false, data, last); return sendMessage(groupid, false, (Object) data, last);
} }
public final int sendRecentMessage(Serializable groupid, byte[] data) { public final int sendRecentMessage(Serializable groupid, byte[] data) {
return sendMessage(groupid, true, data); return sendMessage(groupid, true, (Object) data, true);
} }
public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) { public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) {
return sendMessage(groupid, true, data, last); return sendMessage(groupid, true, (Object) data, last);
} }
public final int sendMessage(Serializable groupid, boolean recent, byte[] data) { public final int sendMessage(Serializable groupid, boolean recent, byte[] data) {
@@ -232,6 +232,28 @@ public abstract class WebSocketNode {
} }
public final int sendMessage(Serializable groupid, boolean recent, byte[] data, boolean last) { public final int sendMessage(Serializable groupid, boolean recent, byte[] data, boolean last) {
return sendMessage(groupid, recent, (Serializable) data, last); return sendMessage(groupid, recent, (Object) data, last);
} }
//--------------------------------------------------------------------------------
public final int sendEachMessage(Serializable groupid, Object message) {
return sendMessage(groupid, false, message, true);
}
public final int sendEachMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, false, message, last);
}
public final int sendRecentMessage(Serializable groupid, Object message) {
return sendMessage(groupid, true, message, true);
}
public final int sendRecentMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, true, message, last);
}
public final int sendMessage(Serializable groupid, boolean recent, Object message) {
return sendMessage(groupid, recent, message, true);
}
} }

View File

@@ -8,11 +8,11 @@ package org.redkale.net.http;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.nio.*; import java.nio.*;
import java.nio.channels.*;
import java.security.*; import java.security.*;
import java.util.*; import java.util.*;
import java.util.logging.*; import java.util.logging.*;
import javax.annotation.*; import javax.annotation.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.service.WebSocketNodeService; import org.redkale.service.WebSocketNodeService;
import org.redkale.util.*; import org.redkale.util.*;
@@ -23,11 +23,12 @@ import org.redkale.util.*;
* WebSocketServlet * WebSocketServlet
* | * |
* | * |
* WebSocketEngine &#38; WebSocketNode * WebSocketEngine
* / \ * WebSocketNode
* / \ * / \
* / \ * / \
* WebSocketGroup1 WebSocketGroup2 * / \
* WebSocketGroup1 WebSocketGroup2
* / \ / \ * / \ / \
* / \ / \ * / \ / \
* WebSocket1 WebSocket2 WebSocket3 WebSocket4 * WebSocket1 WebSocket2 WebSocket3 WebSocket4
@@ -39,10 +40,12 @@ import org.redkale.util.*;
* *
* @author zhangjx * @author zhangjx
*/ */
public abstract class WebSocketServlet extends HttpServlet { public abstract class WebSocketServlet extends HttpServlet implements Resourcable {
@Comment("WebScoket服务器给客户端进行ping操作的间隔时间, 单位: 秒")
public static final String WEBPARAM__LIVEINTERVAL = "liveinterval"; public static final String WEBPARAM__LIVEINTERVAL = "liveinterval";
@Comment("WebScoket服务器给客户端进行ping操作的默认间隔时间, 单位: 秒")
public static final int DEFAILT_LIVEINTERVAL = 60; public static final int DEFAILT_LIVEINTERVAL = 60;
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
@@ -57,9 +60,12 @@ public abstract class WebSocketServlet extends HttpServlet {
} }
} }
//是否用于二进制流传输 @Comment("是否用于二进制流传输")
protected final boolean wsbinary = getClass().getAnnotation(WebSocketBinary.class) != null; protected final boolean wsbinary = getClass().getAnnotation(WebSocketBinary.class) != null;
@Resource
protected JsonConvert jsonConvert;
@Resource(name = "$") @Resource(name = "$")
protected WebSocketNode node; protected WebSocketNode node;
@@ -67,7 +73,7 @@ public abstract class WebSocketServlet extends HttpServlet {
public final void preInit(HttpContext context, AnyValue conf) { public final void preInit(HttpContext context, AnyValue conf) {
InetSocketAddress addr = context.getServerAddress(); InetSocketAddress addr = context.getServerAddress();
this.engine = new WebSocketEngine(addr.getHostString() + ":" + addr.getPort() + "-[" + name() + "]", this.node, logger); this.engine = new WebSocketEngine(addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]", this.node, logger);
if (this.node == null) this.node = createWebSocketNode(); if (this.node == null) this.node = createWebSocketNode();
if (this.node == null) { if (this.node == null) {
this.node = new WebSocketNodeService(); this.node = new WebSocketNodeService();
@@ -84,7 +90,8 @@ public abstract class WebSocketServlet extends HttpServlet {
engine.close(); engine.close();
} }
public String name() { @Override
public String resourceName() {
return this.getClass().getSimpleName().replace("Servlet", "").replace("WebSocket", "").toLowerCase(); return this.getClass().getSimpleName().replace("Servlet", "").replace("WebSocket", "").toLowerCase();
} }
@@ -106,6 +113,7 @@ public abstract class WebSocketServlet extends HttpServlet {
} }
final WebSocket webSocket = this.createWebSocket(); final WebSocket webSocket = this.createWebSocket();
webSocket._engine = engine; webSocket._engine = engine;
webSocket._jsonConvert = jsonConvert;
webSocket._remoteAddress = request.getRemoteAddress(); webSocket._remoteAddress = request.getRemoteAddress();
webSocket._remoteAddr = request.getRemoteAddr(); webSocket._remoteAddr = request.getRemoteAddr();
Serializable sessionid = webSocket.onOpen(request); Serializable sessionid = webSocket.onOpen(request);
@@ -125,7 +133,7 @@ public abstract class WebSocketServlet extends HttpServlet {
response.setHeader("Connection", "Upgrade"); response.setHeader("Connection", "Upgrade");
response.addHeader("Upgrade", "websocket"); response.addHeader("Upgrade", "websocket");
response.addHeader("Sec-WebSocket-Accept", key); response.addHeader("Sec-WebSocket-Accept", key);
response.sendBody((ByteBuffer) null, null, new CompletionHandler<Integer, Void>() { response.sendBody((ByteBuffer) null, null, new AsyncHandler<Integer, Void>() {
@Override @Override
public void completed(Integer result, Void attachment) { public void completed(Integer result, Void attachment) {
@@ -138,7 +146,7 @@ public abstract class WebSocketServlet extends HttpServlet {
} }
webSocket._groupid = groupid; webSocket._groupid = groupid;
engine.add(webSocket); engine.add(webSocket);
context.submit(new WebSocketRunner(context, webSocket, response.removeChannel(), wsbinary)); context.runAsync(new WebSocketRunner(context, webSocket, response.removeChannel(), wsbinary));
response.finish(true); response.finish(true);
} }

View File

@@ -1,156 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.sncp;
import java.util.*;
import java.util.stream.Collectors;
import org.redkale.service.Service;
import org.redkale.util.*;
/**
* Service对象的封装类
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> Service的子类
*/
public final class ServiceWrapper<T extends Service> implements Comparable<ServiceWrapper> {
private static volatile int maxClassNameLength = 0;
private static volatile int maxNameLength = 0;
private final T service;
private final AnyValue conf;
private final String sncpGroup; //自身的组节点名 可能为null
private final Set<String> groups; //所有的组节点,包含自身
private final String name;
private final boolean remote;
private final Class[] types;
public ServiceWrapper(T service, String name, String sncpGroup, Set<String> groups, AnyValue conf) {
this(null, service, name, sncpGroup, groups, conf);
}
@SuppressWarnings("unchecked")
public ServiceWrapper(Class<T> type, T service, String name, String sncpGroup, Set<String> groups, AnyValue conf) {
this.service = service;
this.conf = conf;
this.sncpGroup = sncpGroup;
this.groups = groups;
this.name = name;
this.remote = Sncp.isRemote(service);
ResourceType rty = service.getClass().getAnnotation(ResourceType.class);
this.types = rty == null ? new Class[]{type == null ? (Class<T>) service.getClass() : type} : rty.value();
maxNameLength = Math.max(maxNameLength, name.length());
StringBuilder s = new StringBuilder();
if (this.types.length == 1) {
s.append(types[0].getName());
} else {
s.append('[');
s.append(Arrays.asList(this.types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
}
maxClassNameLength = Math.max(maxClassNameLength, s.length() + 1);
}
public static Class[] parseTypes(final Class<? extends Service> servicetype) {
ResourceType rty = servicetype.getAnnotation(ResourceType.class);
return rty == null ? new Class[]{servicetype} : rty.value();
}
@Override
public String toString() {
return toSimpleString();
}
public String toSimpleString() {
StringBuilder sb = new StringBuilder();
sb.append(remote ? "RemoteService" : "LocalService ");
int len;
if (types.length == 1) {
sb.append("(type= ").append(types[0].getName());
len = maxClassNameLength - types[0].getName().length();
} else {
StringBuilder s = new StringBuilder();
s.append('[');
s.append(Arrays.asList(this.types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
sb.append("(types=").append(s);
len = maxClassNameLength - s.length();
}
for (int i = 0; i < len; i++) {
sb.append(' ');
}
sb.append(", name='").append(name).append("'");
for (int i = 0; i < maxNameLength - name.length(); i++) {
sb.append(' ');
}
sb.append(")");
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null) return false;
if (!(obj instanceof ServiceWrapper)) return false;
ServiceWrapper other = (ServiceWrapper) obj;
return (this.types[0].equals(other.types[0]) && this.remote == other.remote && this.name.equals(other.name) && Objects.equals(this.sncpGroup, other.sncpGroup));
}
@Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + Objects.hashCode(this.types[0]);
hash = 67 * hash + Objects.hashCode(this.sncpGroup);
hash = 67 * hash + Objects.hashCode(this.name);
hash = 67 * hash + (this.remote ? 1 : 0);
return hash;
}
@Override
public int compareTo(ServiceWrapper o) {
int rs = this.types[0].getName().compareTo(o.types[0].getName());
if (rs == 0) rs = this.name.compareTo(o.name);
return rs;
}
public Class[] getTypes() {
return types;
}
public Service getService() {
return service;
}
public AnyValue getConf() {
return conf;
}
public String getName() {
return name;
}
public boolean isRemote() {
return remote;
}
public Set<String> getGroups() {
return groups;
}
}

View File

@@ -11,6 +11,7 @@ import java.net.InetSocketAddress;
import java.security.*; import java.security.*;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.annotation.Resource; import javax.annotation.Resource;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import jdk.internal.org.objectweb.asm.*; import jdk.internal.org.objectweb.asm.*;
@@ -55,11 +56,6 @@ public abstract class Sncp {
private Sncp() { private Sncp() {
} }
public static long nodeid(InetSocketAddress ip) {
byte[] bytes = ip.getAddress().getAddress();
return ((0L + ip.getPort()) << 32) | ((0xffffffff & bytes[0]) << 24) | ((0xffffff & bytes[1]) << 16) | ((0xffff & bytes[2]) << 8) | (0xff & bytes[3]);
}
public static DLong hash(final java.lang.reflect.Method method) { public static DLong hash(final java.lang.reflect.Method method) {
if (method == null) return DLong.ZERO; if (method == null) return DLong.ZERO;
StringBuilder sb = new StringBuilder(); //不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致 StringBuilder sb = new StringBuilder(); //不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致
@@ -97,6 +93,62 @@ public abstract class Sncp {
return dyn != null && dyn.remote(); return dyn != null && dyn.remote();
} }
public static String getResourceName(Service service) {
if (service == null) return null;
Resource res = service.getClass().getAnnotation(Resource.class);
return res == null ? null : res.name();
}
public static Class getServiceType(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_service_type");
ts.setAccessible(true);
return (Class) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_service_type");
}
}
public static Class[] getResourceTypes(Service service) {
if (service == null) return null;
ResourceType types = service.getClass().getAnnotation(ResourceType.class);
return types == null ? new Class[]{getServiceType(service)} : types.value();
}
public static String getSncpGroup(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_sncpGroup");
ts.setAccessible(true);
return (String) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_sncpGroup");
}
}
public static Set<String> getGroups(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_groups");
ts.setAccessible(true);
return (Set) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_groups");
}
}
public static AnyValue getConf(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_conf");
ts.setAccessible(true);
return (AnyValue) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_conf");
}
}
public static SncpClient getSncpClient(Service service) { public static SncpClient getSncpClient(Service service) {
if (service == null) return null; if (service == null) return null;
try { try {
@@ -130,6 +182,73 @@ public abstract class Sncp {
} }
} }
static void checkAsyncModifier(Class param, Method method) {
if (param == AsyncHandler.class) return;
if (Modifier.isFinal(param.getModifiers())) {
throw new RuntimeException("AsyncHandler Type Parameter on {" + method + "} cannot final modifier");
}
if (!Modifier.isPublic(param.getModifiers())) {
throw new RuntimeException("AsyncHandler Type Parameter on {" + method + "} must be public modifier");
}
if (param.isInterface()) return;
boolean constructorflag = false;
for (Constructor c : param.getDeclaredConstructors()) {
if (c.getParameterCount() == 0) {
int mod = c.getModifiers();
if (Modifier.isPublic(mod) || Modifier.isProtected(mod)) {
constructorflag = true;
break;
}
}
}
if (param.getDeclaredConstructors().length == 0) constructorflag = true;
if (!constructorflag) throw new RuntimeException(param + " must have a empty parameter Constructor");
for (Method m : param.getMethods()) {
if (m.getName().equals("completed") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s completed method cannot final modifier");
} else if (m.getName().equals("failed") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s failed method cannot final modifier");
} else if (m.getName().equals("sncp_getParams") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_getParams method cannot final modifier");
} else if (m.getName().equals("sncp_setParams") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_setParams method cannot final modifier");
} else if (m.getName().equals("sncp_setFuture") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_setFuture method cannot final modifier");
} else if (m.getName().equals("sncp_getFuture") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_getFuture method cannot final modifier");
}
}
}
public static String toSimpleString(final Service service, int maxNameLength, int maxClassNameLength) {
StringBuilder sb = new StringBuilder();
sb.append(isRemote(service) ? "RemoteService" : "LocalService ");
int len;
Class[] types = getResourceTypes(service);
String name = getResourceName(service);
if (types.length == 1) {
sb.append("(type= ").append(types[0].getName());
len = maxClassNameLength - types[0].getName().length();
} else {
StringBuilder s = new StringBuilder();
s.append('[');
s.append(Arrays.asList(types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
sb.append("(types=").append(s);
len = maxClassNameLength - s.length();
}
for (int i = 0; i < len; i++) {
sb.append(' ');
}
sb.append(", name='").append(name).append("'");
for (int i = 0; i < maxNameLength - name.length(); i++) {
sb.append(' ');
}
sb.append(")");
return sb.toString();
}
/** /**
* <blockquote><pre> * <blockquote><pre>
* public class TestService implements Service{ * public class TestService implements Service{
@@ -139,16 +258,16 @@ public abstract class Sncp {
* } * }
* *
* &#64;RpcMultiRun(selfrun = false) * &#64;RpcMultiRun(selfrun = false)
public void createSomeThing(TestBean bean){ * public void createSomeThing(TestBean bean){
//do something * //do something
} * }
*
&#64;RpcMultiRun * &#64;RpcMultiRun
public String updateSomeThing(String id){ * public String updateSomeThing(String id){
return "hello" + id; * return "hello" + id;
} * }
} * }
</pre></blockquote> * </pre></blockquote>
* *
* <blockquote><pre> * <blockquote><pre>
* &#64;Resource(name = "") * &#64;Resource(name = "")
@@ -156,12 +275,20 @@ public abstract class Sncp {
* &#64;ResourceType({TestService.class}) * &#64;ResourceType({TestService.class})
* public final class _DynLocalTestService extends TestService{ * public final class _DynLocalTestService extends TestService{
* *
* private static final Class _redkale_service_type = TestService.class;
*
* &#64;Resource * &#64;Resource
* private BsonConvert _redkale_bsonConvert; * private BsonConvert _redkale_bsonConvert;
* *
* &#64;Resource * &#64;Resource
* private JsonConvert _redkale_jsonConvert; * private JsonConvert _redkale_jsonConvert;
* *
* private AnyValue _redkale_conf;
*
* private String _redkale_sncpGroup; //自身的组节点名 可能为null
*
* private Set&lt;String&gt; groups; //所有的组节点,包含自身
*
* private Transport _redkale_sameGroupTransport; * private Transport _redkale_sameGroupTransport;
* *
* private Transport[] _redkale_diffGroupTransports; * private Transport[] _redkale_diffGroupTransports;
@@ -184,8 +311,8 @@ public abstract class Sncp {
* public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){ * public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
* if(selfrunnable) super.createSomeThing(bean); * if(selfrunnable) super.createSomeThing(bean);
* if (_redkale_client== null) return; * if (_redkale_client== null) return;
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _sameGroupTransport, 0, true, false, false, bean); * if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_sameGroupTransport, 0, true, false, false, bean);
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _diffGroupTransports, 0, true, true, false, bean); * if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_diffGroupTransports, 0, true, true, false, bean);
* } * }
* *
* &#64;Override * &#64;Override
@@ -196,9 +323,9 @@ public abstract class Sncp {
* &#64;SncpDyn(remote = false, index = 1) * &#64;SncpDyn(remote = false, index = 1)
* public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){ * public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
* String rs = super.updateSomeThing(id); * String rs = super.updateSomeThing(id);
* if (_redkale_client== null) return; * if (_redkale_client== null) return rs;
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _sameGroupTransport, 1, true, false, false, id); * if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_sameGroupTransport, 1, true, false, false, id);
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _diffGroupTransports, 1, true, true, false, id); * if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_diffGroupTransports, 1, true, true, false, id);
* return rs; * return rs;
* } * }
* } * }
@@ -206,40 +333,43 @@ public abstract class Sncp {
* *
* 创建Service的本地模式Class * 创建Service的本地模式Class
* *
* @param <T> Service子类 * @param <T> Service子类
* @param name 资源名 * @param name 资源名
* @param serviceClass Service类 * @param serviceImplClass Service类
* *
* @return Service实例 * @return Service实例
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected static <T extends Service> Class<? extends T> createLocalServiceClass(final String name, final Class<T> serviceClass) { protected static <T extends Service> Class<? extends T> createLocalServiceClass(final String name, final Class<T> serviceImplClass) {
if (serviceClass == null) return null; if (serviceImplClass == null) return null;
if (!Service.class.isAssignableFrom(serviceClass)) return serviceClass; if (!Service.class.isAssignableFrom(serviceImplClass)) return serviceImplClass;
int mod = serviceClass.getModifiers(); int mod = serviceImplClass.getModifiers();
if (!java.lang.reflect.Modifier.isPublic(mod)) return serviceClass; if (!java.lang.reflect.Modifier.isPublic(mod)) return serviceImplClass;
if (java.lang.reflect.Modifier.isAbstract(mod)) return serviceClass; if (java.lang.reflect.Modifier.isAbstract(mod)) return serviceImplClass;
final List<Method> methods = SncpClient.parseMethod(serviceClass); final List<Method> methods = SncpClient.parseMethod(serviceImplClass);
final String supDynName = serviceClass.getName().replace('.', '/'); final String supDynName = serviceImplClass.getName().replace('.', '/');
final String clientName = SncpClient.class.getName().replace('.', '/'); final String clientName = SncpClient.class.getName().replace('.', '/');
final String clientDesc = Type.getDescriptor(SncpClient.class); final String clientDesc = Type.getDescriptor(SncpClient.class);
final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class); final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class);
final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class); final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
final String stringDesc = Type.getDescriptor(String.class);
final String anyValueDesc = Type.getDescriptor(AnyValue.class);
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class); final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
final String transportDesc = Type.getDescriptor(Transport.class); final String transportDesc = Type.getDescriptor(Transport.class);
final String transportsDesc = Type.getDescriptor(Transport[].class); final String transportsDesc = Type.getDescriptor(Transport[].class);
ClassLoader loader = Sncp.class.getClassLoader(); ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + serviceClass.getSimpleName(); String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + serviceImplClass.getSimpleName();
if (!name.isEmpty()) { if (!name.isEmpty()) {
boolean normal = true; boolean normal = true;
for (char ch : name.toCharArray()) { for (char ch : name.toCharArray()) {
if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) normal = false; if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) normal = false;
} }
if (!normal) throw new RuntimeException(serviceImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z");
newDynName += "_" + (normal ? name : hash(name)); newDynName += "_" + (normal ? name : hash(name));
} }
try { try {
return (Class<T>) Class.forName(newDynName.replace('/', '.')); return (Class<T>) Class.forName(newDynName.replace('/', '.'));
} catch (Exception ex) { } catch (Throwable ex) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
@@ -259,7 +389,7 @@ public abstract class Sncp {
av0.visitEnd(); av0.visitEnd();
} }
{ //给新类加上 原有的Annotation { //给新类加上 原有的Annotation
for (Annotation ann : serviceClass.getAnnotations()) { for (Annotation ann : serviceImplClass.getAnnotations()) {
if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) continue; if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) continue;
visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
} }
@@ -268,9 +398,9 @@ public abstract class Sncp {
av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true); av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
{ {
AnnotationVisitor av1 = av0.visitArray("value"); AnnotationVisitor av1 = av0.visitArray("value");
ResourceType rty = serviceClass.getAnnotation(ResourceType.class); ResourceType rty = serviceImplClass.getAnnotation(ResourceType.class);
if (rty == null) { if (rty == null) {
av1.visit(null, Type.getType(Type.getDescriptor(serviceClass))); av1.visit(null, Type.getType(Type.getDescriptor(serviceImplClass)));
} else { } else {
for (Class cl : rty.value()) { for (Class cl : rty.value()) {
av1.visit(null, Type.getType(Type.getDescriptor(cl))); av1.visit(null, Type.getType(Type.getDescriptor(cl)));
@@ -280,7 +410,10 @@ public abstract class Sncp {
} }
av0.visitEnd(); av0.visitEnd();
} }
{
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, FIELDPREFIX + "_service_type", "Ljava/lang/Class;", null, null);
fv.visitEnd();
}
{ {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null); fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null);
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true); av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
@@ -293,6 +426,18 @@ public abstract class Sncp {
av0.visitEnd(); av0.visitEnd();
fv.visitEnd(); fv.visitEnd();
} }
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncpGroup", stringDesc, null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_groups", "Ljava/util/Set;", "Ljava/util/Set<Ljava/lang/String;>;", null);
fv.visitEnd();
}
{ {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sameGroupTransport", transportDesc, null, null); fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sameGroupTransport", transportDesc, null, null);
fv.visitEnd(); fv.visitEnd();
@@ -310,6 +455,14 @@ public abstract class Sncp {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_selfstring", "Ljava/lang/String;", null, null); fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_selfstring", "Ljava/lang/String;", null, null);
fv.visitEnd(); fv.visitEnd();
} }
{//静态构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null));
mv.visitLdcInsn(Type.getType(Type.getDescriptor(serviceImplClass)));
mv.visitFieldInsn(PUTSTATIC, newDynName, FIELDPREFIX + "_service_type", "Ljava/lang/Class;");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 0);
mv.visitEnd();
}
{ //构造函数 { //构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)); mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true); //mv.setDebug(true);
@@ -362,7 +515,13 @@ public abstract class Sncp {
mv.visitInsn(mrun.samerun() ? ICONST_1 : ICONST_0); mv.visitInsn(mrun.samerun() ? ICONST_1 : ICONST_0);
mv.visitInsn(mrun.diffrun() ? ICONST_1 : ICONST_0); mv.visitInsn(mrun.diffrun() ? ICONST_1 : ICONST_0);
int varindex = 0; int varindex = 0;
boolean handlerFuncFlag = false;
for (Class pt : paramtypes) { for (Class pt : paramtypes) {
if (AsyncHandler.class.isAssignableFrom(pt)) {
if (handlerFuncFlag) throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
checkAsyncModifier(pt, method);
handlerFuncFlag = true;
}
if (pt.isPrimitive()) { if (pt.isPrimitive()) {
if (pt == long.class) { if (pt == long.class) {
mv.visitVarInsn(LLOAD, ++varindex); mv.visitVarInsn(LLOAD, ++varindex);
@@ -403,8 +562,15 @@ public abstract class Sncp {
//mv.setDebug(true); //mv.setDebug(true);
{ //给参数加上 Annotation { //给参数加上 Annotation
final Annotation[][] anns = method.getParameterAnnotations(); final Annotation[][] anns = method.getParameterAnnotations();
boolean handlerAttachFlag = false;
for (int k = 0; k < anns.length; k++) { for (int k = 0; k < anns.length; k++) {
for (Annotation ann : anns[k]) { for (Annotation ann : anns[k]) {
if (ann.annotationType() == RpcAttachment.class) {
if (handlerAttachFlag) {
throw new RuntimeException(method + " have more than one @RpcAttachment parameter");
}
handlerAttachFlag = true;
}
if (ann instanceof SncpDyn || ann instanceof RpcMultiRun) continue; //必须过滤掉 RpcMultiRun、SncpDyn否则生成远程模式Service时会出错 if (ann instanceof SncpDyn || ann instanceof RpcMultiRun) continue; //必须过滤掉 RpcMultiRun、SncpDyn否则生成远程模式Service时会出错
visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
} }
@@ -501,7 +667,7 @@ public abstract class Sncp {
mv.visitVarInsn(ALOAD, 0); //传递 _sameGroupTransport mv.visitVarInsn(ALOAD, 0); //传递 _sameGroupTransport
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sameGroupTransport", transportDesc); mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sameGroupTransport", transportDesc);
final int preparams = 4; //调用selfrunnable之前的参数个数; _client/_bsonConvert/_jsonConvert/_sameGroupTransport final int preparams = 3; //调用selfrunnable之前的参数个数; _client/_bsonConvert/_jsonConvert/_sameGroupTransport
if (index <= 5) { //第几个 SncpAction if (index <= 5) { //第几个 SncpAction
mv.visitInsn(ICONST_0 + index); mv.visitInsn(ICONST_0 + index);
@@ -524,13 +690,13 @@ public abstract class Sncp {
mv.visitInsn(DUP); mv.visitInsn(DUP);
mv.visitInsn(ICONST_1); mv.visitInsn(ICONST_1);
mv.visitInsn(ICONST_0); //第个参数 samerunnable mv.visitInsn(ICONST_0); //第个参数 samerunnable
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitInsn(AASTORE); mv.visitInsn(AASTORE);
mv.visitInsn(DUP); mv.visitInsn(DUP);
mv.visitInsn(ICONST_2); mv.visitInsn(ICONST_2);
mv.visitInsn(ICONST_0); //第个参数 diffrunnable mv.visitInsn(ICONST_0); //第个参数 diffrunnable
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitInsn(AASTORE); mv.visitInsn(AASTORE);
@@ -719,6 +885,10 @@ public abstract class Sncp {
} }
} }
public static <T extends Service> T createSimpleLocalService(final String name, final Class<T> serviceImplClass, final InetSocketAddress clientAddress, final Transport sameGroupTransport) {
return createLocalService(name, null, ResourceFactory.root(), serviceImplClass, clientAddress, null, new HashSet<>(), null, sameGroupTransport, null);
}
/** /**
* *
* 创建本地模式Service实例 * 创建本地模式Service实例
@@ -727,18 +897,30 @@ public abstract class Sncp {
* @param name 资源名 * @param name 资源名
* @param executor 线程池 * @param executor 线程池
* @param resourceFactory 资源容器 * @param resourceFactory 资源容器
* @param serviceClass Service类 * @param serviceImplClass Service类
* @param clientAddress 本地IP地址 * @param clientAddress 本地IP地址
* @param sncpGroup 自身的组节点名 可能为null
* @param groups 所有的组节点,包含自身
* @param conf 启动配置项
* @param sameGroupTransport 同组的通信组件 * @param sameGroupTransport 同组的通信组件
* @param diffGroupTransports 异组的通信组件列表 * @param diffGroupTransports 异组的通信组件列表
* *
* @return Service的本地模式实例 * @return Service的本地模式实例
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends Service> T createLocalService(final String name, final Consumer<Runnable> executor, final ResourceFactory resourceFactory, public static <T extends Service> T createLocalService(
final Class<T> serviceClass, final InetSocketAddress clientAddress, final Transport sameGroupTransport, final Collection<Transport> diffGroupTransports) { final String name,
final Consumer<Runnable> executor,
final ResourceFactory resourceFactory,
final Class<T> serviceImplClass,
final InetSocketAddress clientAddress,
final String sncpGroup,
final Set<String> groups,
final AnyValue conf,
final Transport sameGroupTransport,
final Collection<Transport> diffGroupTransports) {
try { try {
final Class newClazz = createLocalServiceClass(name, serviceClass); final Class newClazz = createLocalServiceClass(name, serviceImplClass);
T rs = (T) newClazz.newInstance(); T rs = (T) newClazz.newInstance();
//-------------------------------------- //--------------------------------------
Service remoteService = null; Service remoteService = null;
@@ -770,7 +952,7 @@ public abstract class Sncp {
} }
} }
if (remoteService == null && remoteTransport != null) { if (remoteService == null && remoteTransport != null) {
remoteService = createRemoteService(name, executor, serviceClass, clientAddress, remoteTransport); remoteService = createRemoteService(name, executor, serviceImplClass, clientAddress, sncpGroup, groups, conf, remoteTransport);
} }
if (remoteService != null) field.set(rs, remoteService); if (remoteService != null) field.set(rs, remoteService);
} }
@@ -781,7 +963,7 @@ public abstract class Sncp {
try { try {
Field e = newClazz.getDeclaredField(FIELDPREFIX + "_client"); Field e = newClazz.getDeclaredField(FIELDPREFIX + "_client");
e.setAccessible(true); e.setAccessible(true);
client = new SncpClient(name, serviceClass, rs, executor, false, newClazz, clientAddress); client = new SncpClient(name, serviceImplClass, rs, executor, false, newClazz, clientAddress);
e.set(rs, client); e.set(rs, client);
} catch (NoSuchFieldException ne) { } catch (NoSuchFieldException ne) {
} }
@@ -793,13 +975,13 @@ public abstract class Sncp {
sb.append(", serviceid = ").append(client.getServiceid()); sb.append(", serviceid = ").append(client.getServiceid());
sb.append(", serviceversion = ").append(client.getServiceversion()); sb.append(", serviceversion = ").append(client.getServiceversion());
sb.append(", action.size = ").append(client.getActionCount()); sb.append(", action.size = ").append(client.getActionCount());
List<String> groups = new ArrayList<>(); // List<String> groups = new ArrayList<>();
if (sameGroupTransport != null) groups.add(sameGroupTransport.getName()); // if (sameGroupTransport != null) groups.add(sameGroupTransport.getName());
if (diffGroupTransports != null) { // if (diffGroupTransports != null) {
for (Transport t : diffGroupTransports) { // for (Transport t : diffGroupTransports) {
groups.add(t.getName()); // groups.add(t.getName());
} // }
} // }
sb.append(", address = ").append(clientAddress).append(", groups = ").append(groups); sb.append(", address = ").append(clientAddress).append(", groups = ").append(groups);
sb.append(", sameaddrs = ").append(sameGroupTransport == null ? null : Arrays.asList(sameGroupTransport.getRemoteAddresses())); sb.append(", sameaddrs = ").append(sameGroupTransport == null ? null : Arrays.asList(sameGroupTransport.getRemoteAddresses()));
@@ -819,6 +1001,21 @@ public abstract class Sncp {
s.set(rs, sb.toString()); s.set(rs, sb.toString());
} }
if (client == null) return rs; if (client == null) return rs;
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncpGroup");
c.setAccessible(true);
c.set(rs, sncpGroup);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_groups");
c.setAccessible(true);
c.set(rs, groups);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf");
c.setAccessible(true);
c.set(rs, conf);
}
{ {
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sameGroupTransport"); Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sameGroupTransport");
c.setAccessible(true); c.setAccessible(true);
@@ -838,6 +1035,10 @@ public abstract class Sncp {
} }
public static <T extends Service> T createSimpleRemoteService(final String name, final Class<T> serviceTypeOrImplClass, final InetSocketAddress clientAddress, final Transport transport) {
return createRemoteService(name, null, serviceTypeOrImplClass, clientAddress, (String) null, new HashSet<>(), (AnyValue) null, transport);
}
/** /**
* <blockquote><pre> * <blockquote><pre>
* &#64;Resource(name = "") * &#64;Resource(name = "")
@@ -845,12 +1046,20 @@ public abstract class Sncp {
* &#64;ResourceType({TestService.class}) * &#64;ResourceType({TestService.class})
* public final class _DynRemoteTestService extends TestService{ * public final class _DynRemoteTestService extends TestService{
* *
* private static final Class _redkale_service_type = TestService.class;
*
* &#64;Resource * &#64;Resource
* private BsonConvert _redkale_bsonConvert; * private BsonConvert _redkale_bsonConvert;
* *
* &#64;Resource * &#64;Resource
* private JsonConvert _redkale_jsonConvert; * private JsonConvert _redkale_jsonConvert;
* *
* private String _redkale_sncpGroup; //自身的组节点名 可能为null
*
* private Set&lt;String&gt; groups; //所有的组节点,包含自身
*
* private AnyValue _redkale_conf;
*
* private Transport _redkale_transport; * private Transport _redkale_transport;
* *
* private SncpClient _redkale_client; * private SncpClient _redkale_client;
@@ -891,37 +1100,48 @@ public abstract class Sncp {
* *
* 创建远程模式的Service实例 * 创建远程模式的Service实例
* *
* @param <T> Service泛型 * @param <T> Service泛型
* @param name 资源名 * @param name 资源名
* @param executor 线程池 * @param executor 线程池
* @param serviceClass Service类 * @param serviceTypeOrImplClass Service类
* @param clientAddress 本地IP地址 * @param clientAddress 本地IP地址
* @param transport 通信组件 * @param sncpGroup 自身的组节点名 可能为null
* @param groups 所有的组节点,包含自身
* @param conf 启动配置项
* @param transport 通信组件
* *
* @return Service的远程模式实例 * @return Service的远程模式实例
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends Service> T createRemoteService(final String name, final Consumer<Runnable> executor, final Class<T> serviceClass, public static <T extends Service> T createRemoteService(
final InetSocketAddress clientAddress, final Transport transport) { final String name,
if (serviceClass == null) return null; final Consumer<Runnable> executor,
if (!Service.class.isAssignableFrom(serviceClass)) return null; final Class<T> serviceTypeOrImplClass,
int mod = serviceClass.getModifiers(); final InetSocketAddress clientAddress,
boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceClass.isInterface()); final String sncpGroup,
final Set<String> groups,
final AnyValue conf,
final Transport transport) {
if (serviceTypeOrImplClass == null) return null;
if (!Service.class.isAssignableFrom(serviceTypeOrImplClass)) return null;
int mod = serviceTypeOrImplClass.getModifiers();
boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceTypeOrImplClass.isInterface());
if (!java.lang.reflect.Modifier.isPublic(mod)) return null; if (!java.lang.reflect.Modifier.isPublic(mod)) return null;
final String supDynName = serviceClass.getName().replace('.', '/'); final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/');
final String clientName = SncpClient.class.getName().replace('.', '/'); final String clientName = SncpClient.class.getName().replace('.', '/');
final String clientDesc = Type.getDescriptor(SncpClient.class); final String clientDesc = Type.getDescriptor(SncpClient.class);
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class); final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class); final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class);
final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class); final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
final String transportDesc = Type.getDescriptor(Transport.class); final String transportDesc = Type.getDescriptor(Transport.class);
final String stringDesc = Type.getDescriptor(String.class);
final String anyValueDesc = Type.getDescriptor(AnyValue.class); final String anyValueDesc = Type.getDescriptor(AnyValue.class);
ClassLoader loader = Sncp.class.getClassLoader(); ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceClass.getSimpleName(); String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceTypeOrImplClass.getSimpleName();
try { try {
Class newClazz = Class.forName(newDynName.replace('/', '.')); Class newClazz = Class.forName(newDynName.replace('/', '.'));
T rs = (T) newClazz.newInstance(); T rs = (T) newClazz.newInstance();
SncpClient client = new SncpClient(name, serviceClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress); SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client"); Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
c.setAccessible(true); c.setAccessible(true);
c.set(rs, client); c.set(rs, client);
@@ -942,7 +1162,7 @@ public abstract class Sncp {
s.set(rs, sb.toString()); s.set(rs, sb.toString());
} }
return rs; return rs;
} catch (Exception ex) { } catch (Throwable ex) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
@@ -950,7 +1170,7 @@ public abstract class Sncp {
AsmMethodVisitor mv; AsmMethodVisitor mv;
AnnotationVisitor av0; AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, serviceClass.isInterface() ? "java/lang/Object" : supDynName, serviceClass.isInterface() ? new String[]{supDynName} : null); cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, serviceTypeOrImplClass.isInterface() ? new String[]{supDynName} : null);
{ {
av0 = cw.visitAnnotation("Ljavax/annotation/Resource;", true); av0 = cw.visitAnnotation("Ljavax/annotation/Resource;", true);
av0.visit("name", name); av0.visit("name", name);
@@ -960,9 +1180,9 @@ public abstract class Sncp {
av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true); av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
{ {
AnnotationVisitor av1 = av0.visitArray("value"); AnnotationVisitor av1 = av0.visitArray("value");
ResourceType rty = serviceClass.getAnnotation(ResourceType.class); ResourceType rty = serviceTypeOrImplClass.getAnnotation(ResourceType.class);
if (rty == null) { if (rty == null) {
av1.visit(null, Type.getType(Type.getDescriptor(serviceClass))); av1.visit(null, Type.getType(Type.getDescriptor(serviceTypeOrImplClass)));
} else { } else {
for (Class cl : rty.value()) { for (Class cl : rty.value()) {
av1.visit(null, Type.getType(Type.getDescriptor(cl))); av1.visit(null, Type.getType(Type.getDescriptor(cl)));
@@ -978,11 +1198,15 @@ public abstract class Sncp {
av0.visitEnd(); av0.visitEnd();
} }
{ //给新类加上 原有的Annotation { //给新类加上 原有的Annotation
for (Annotation ann : serviceClass.getAnnotations()) { for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) {
if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) continue; if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) continue;
visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
} }
} }
{
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, FIELDPREFIX + "_service_type", "Ljava/lang/Class;", null, null);
fv.visitEnd();
}
{ {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null); fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null);
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true); av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
@@ -995,6 +1219,18 @@ public abstract class Sncp {
av0.visitEnd(); av0.visitEnd();
fv.visitEnd(); fv.visitEnd();
} }
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncpGroup", stringDesc, null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_groups", "Ljava/util/Set;", "Ljava/util/Set<Ljava/lang/String;>;", null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
fv.visitEnd();
}
{ {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_transport", transportDesc, null, null); fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_transport", transportDesc, null, null);
fv.visitEnd(); fv.visitEnd();
@@ -1007,11 +1243,19 @@ public abstract class Sncp {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_selfstring", "Ljava/lang/String;", null, null); fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_selfstring", "Ljava/lang/String;", null, null);
fv.visitEnd(); fv.visitEnd();
} }
{//静态构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null));
mv.visitLdcInsn(Type.getType(Type.getDescriptor(serviceTypeOrImplClass)));
mv.visitFieldInsn(PUTSTATIC, newDynName, FIELDPREFIX + "_service_type", "Ljava/lang/Class;");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 0);
mv.visitEnd();
}
{ //构造函数 { //构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)); mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true); //mv.setDebug(true);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, serviceClass.isInterface() ? "java/lang/Object" : supDynName, "<init>", "()V", false); mv.visitMethodInsn(INVOKESPECIAL, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, "<init>", "()V", false);
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
mv.visitMaxs(1, 1); mv.visitMaxs(1, 1);
mv.visitEnd(); mv.visitEnd();
@@ -1047,7 +1291,7 @@ public abstract class Sncp {
mv.visitEnd(); mv.visitEnd();
} }
int i = -1; int i = -1;
for (final SncpAction entry : SncpClient.getSncpActions(realed ? createLocalServiceClass(name, serviceClass) : serviceClass)) { for (final SncpAction entry : SncpClient.getSncpActions(realed ? createLocalServiceClass(name, serviceTypeOrImplClass) : serviceTypeOrImplClass)) {
final int index = ++i; final int index = ++i;
final java.lang.reflect.Method method = entry.method; final java.lang.reflect.Method method = entry.method;
{ {
@@ -1156,13 +1400,32 @@ public abstract class Sncp {
}.loadClass(newDynName.replace('/', '.'), bytes); }.loadClass(newDynName.replace('/', '.'), bytes);
try { try {
T rs = (T) newClazz.newInstance(); T rs = (T) newClazz.newInstance();
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client"); SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
c.setAccessible(true); {
SncpClient client = new SncpClient(name, serviceClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress); Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
c.set(rs, client); c.setAccessible(true);
Field t = newClazz.getDeclaredField(FIELDPREFIX + "_transport"); c.set(rs, client);
t.setAccessible(true); }
t.set(rs, transport); {
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf");
c.setAccessible(true);
c.set(rs, conf);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncpGroup");
c.setAccessible(true);
c.set(rs, sncpGroup);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_groups");
c.setAccessible(true);
c.set(rs, groups);
}
{
Field t = newClazz.getDeclaredField(FIELDPREFIX + "_transport");
t.setAccessible(true);
t.set(rs, transport);
}
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(newClazz.getName()).append("{name = '").append(name); sb.append(newClazz.getName()).append("{name = '").append(name);

View File

@@ -0,0 +1,307 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.sncp;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.convert.bson.*;
import org.redkale.net.sncp.SncpDynServlet.SncpServletAction;
import org.redkale.util.*;
/**
* 异步回调函数 <br>
*
* public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler
*
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <V> 结果对象的泛型
* @param <A> 附件对象的泛型
*/
public interface SncpAsyncHandler<V, A> extends AsyncHandler<V, A> {
public Object[] sncp_getParams();
public void sncp_setParams(Object... params);
public void sncp_setFuture(CompletableFuture future);
public CompletableFuture sncp_getFuture();
static class Factory {
/**
* <blockquote><pre>
*
* 考虑点:
* 1、AsyncHandler子类是接口且还有其他多个方法
* 2、AsyncHandler子类是类 需要继承,且必须有空参数构造函数
* 3、AsyncHandler子类无论是接口还是类都可能存在其他泛型
*
* public class XXXAsyncHandler_DyncSncpAsyncHandler_4323 extends XXXAsyncHandler implements SncpAsyncHandler {
*
* private SncpAsyncHandler sncphandler;
*
* private CompletableFuture sncpfuture;
*
* &#64;java.beans.ConstructorProperties({"sncphandler"})
* public XXXAsyncHandler_DyncSncpAsyncHandler_4323(SncpAsyncHandler sncphandler) {
* super();
* this.sncphandler = sncphandler;
* }
*
* &#64;Override
* public void completed(Object result, Object attachment) {
* sncphandler.completed(result, attachment);
* }
*
* &#64;Override
* public void failed(Throwable exc, Object attachment) {
* sncphandler.failed(exc, attachment);
* }
*
* &#64;Override
* public Object[] sncp_getParams() {
* return sncphandler.sncp_getParams();
* }
*
* &#64;Override
* public void sncp_setParams(Object... params) {
* sncphandler.sncp_setParams(params);
* }
*
* &#64;Override
* public void sncp_setFuture(CompletableFuture future) {
* this.sncpfuture = future;
* }
*
* &#64;Override
* public CompletableFuture sncp_getFuture() {
* return this.sncpfuture;
* }
* }
*
* </pre></blockquote>
*
* @param handlerClass AsyncHandler类型或子类
*
* @return Creator
*/
public static Creator<SncpAsyncHandler> createCreator(Class<? extends AsyncHandler> handlerClass) {
//-------------------------------------------------------------
final boolean handlerinterface = handlerClass.isInterface();
final String handlerClassName = handlerClass.getName().replace('.', '/');
final String sncpHandlerName = SncpAsyncHandler.class.getName().replace('.', '/');
final String sncpHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class);
final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class);
final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + SncpAsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
AsmMethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName});
{ //handler 属性
fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null);
fv.visitEnd();
}
{ //future 属性
fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null);
fv.visitEnd();
}
{//构造方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + sncpHandlerDesc + ")V", null, null));
//mv.setDebug(true);
{
av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "sncphandler");
av1.visitEnd();
}
av0.visitEnd();
}
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
Class returnType = method.getReturnType();
if (returnType == void.class) {
mv.visitInsn(RETURN);
mv.visitMaxs(0, 1);
} else if (returnType.isPrimitive()) {
mv.visitInsn(ICONST_0);
if (returnType == long.class) {
mv.visitInsn(LRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == float.class) {
mv.visitInsn(FRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == double.class) {
mv.visitInsn(DRETURN);
mv.visitMaxs(2, 1);
} else {
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
}
} else {
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
}
mv.visitEnd();
}
}
{ // sncp_getParams
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{ // sncp_setParams
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{ // sncp_setFuture
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{ // sncp_getFuture
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Class<SncpAsyncHandler> newHandlerClazz = (Class<SncpAsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
return Creator.create(newHandlerClazz);
}
}
static class DefaultSncpAsyncHandler<V, A> implements SncpAsyncHandler<V, A> {
//为了在回调函数中调用_callParameter方法
protected Object[] params;
protected SncpServletAction action;
protected BsonReader in;
protected BsonWriter out;
protected SncpRequest request;
protected SncpResponse response;
protected CompletableFuture future;
public DefaultSncpAsyncHandler(SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) {
this.action = action;
this.in = in;
this.out = out;
this.request = request;
this.response = response;
}
@Override
public void completed(Object result, Object attachment) {
try {
action._callParameter(out, sncp_getParams());
action.convert.convertTo(out, Object.class, result);
response.finish(0, out);
} catch (Exception e) {
failed(e, attachment);
} finally {
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
}
}
@Override
public void failed(Throwable exc, Object attachment) {
response.getContext().getLogger().log(Level.INFO, "sncp execute error(" + request + ")", exc);
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
}
@Override
public Object[] sncp_getParams() {
return params;
}
@Override
public void sncp_setParams(Object... params) {
this.params = params;
}
@Override
public void sncp_setFuture(CompletableFuture future) {
this.future = future;
}
@Override
public CompletableFuture sncp_getFuture() {
return this.future;
}
}
}

View File

@@ -41,35 +41,66 @@ public final class SncpClient {
protected final Type[] paramTypes; protected final Type[] paramTypes;
protected final Class[] paramClass;
protected final Attribute[] paramAttrs; // 为null表示无RpcCall处理index=0固定为null, 其他为参数标记的RpcCall回调方法 protected final Attribute[] paramAttrs; // 为null表示无RpcCall处理index=0固定为null, 其他为参数标记的RpcCall回调方法
protected final int handlerFuncParamIndex;
protected final int handlerAttachParamIndex;
protected final int addressTargetParamIndex; protected final int addressTargetParamIndex;
protected final int addressSourceParamIndex; protected final int addressSourceParamIndex;
public SncpAction(Method method, DLong actionid) { protected final boolean boolReturnTypeFuture; // 返回结果类型是否为 CompletableFuture
this.actionid = actionid;
protected final Creator<? extends CompletableFuture> futureCreator;
public SncpAction(final Class clazz, Method method, DLong actionid) {
this.actionid = actionid == null ? Sncp.hash(method) : actionid;
Type rt = method.getGenericReturnType(); Type rt = method.getGenericReturnType();
if (rt instanceof TypeVariable) { if (rt instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) rt; TypeVariable tv = (TypeVariable) rt;
if (tv.getBounds().length == 1) rt = tv.getBounds()[0]; if (tv.getBounds().length == 1) rt = tv.getBounds()[0];
} }
this.resultTypes = rt == void.class ? null : rt; this.resultTypes = rt == void.class ? null : rt;
this.boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
this.futureCreator = boolReturnTypeFuture ? Creator.create((Class<? extends CompletableFuture>) method.getReturnType()) : null;
this.paramTypes = method.getGenericParameterTypes(); this.paramTypes = method.getGenericParameterTypes();
this.paramClass = method.getParameterTypes();
this.method = method; this.method = method;
Annotation[][] anns = method.getParameterAnnotations(); Annotation[][] anns = method.getParameterAnnotations();
int targetAddrIndex = -1; int targetAddrIndex = -1;
int sourceAddrIndex = -1; int sourceAddrIndex = -1;
int handlerAttachIndex = -1;
int handlerFuncIndex = -1;
boolean hasattr = false; boolean hasattr = false;
Attribute[] atts = new Attribute[paramTypes.length + 1]; Attribute[] atts = new Attribute[paramTypes.length + 1];
if (anns.length > 0) { if (anns.length > 0) {
Class<?>[] params = method.getParameterTypes(); Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
if (AsyncHandler.class.isAssignableFrom(params[i])) {
if (boolReturnTypeFuture) {
throw new RuntimeException(method + " have both AsyncHandler and CompletableFuture");
}
if (handlerFuncIndex >= 0) {
throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
}
Sncp.checkAsyncModifier(params[i], method);
handlerFuncIndex = i;
break;
}
}
for (int i = 0; i < anns.length; i++) { for (int i = 0; i < anns.length; i++) {
if (anns[i].length > 0) { if (anns[i].length > 0) {
for (Annotation ann : anns[i]) { for (Annotation ann : anns[i]) {
if (ann.annotationType() == RpcTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) { if (ann.annotationType() == RpcAttachment.class) {
if (handlerAttachIndex >= 0) {
throw new RuntimeException(method + " have more than one @RpcAttachment parameter");
}
handlerAttachIndex = i;
} else if (ann.annotationType() == RpcTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
targetAddrIndex = i; targetAddrIndex = i;
} else if (ann.annotationType() == RpcSourceAddress.class && SocketAddress.class.isAssignableFrom(params[i])) { } else if (ann.annotationType() == RpcSourceAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
sourceAddrIndex = i; sourceAddrIndex = i;
@@ -91,7 +122,12 @@ public final class SncpClient {
} }
this.addressTargetParamIndex = targetAddrIndex; this.addressTargetParamIndex = targetAddrIndex;
this.addressSourceParamIndex = sourceAddrIndex; this.addressSourceParamIndex = sourceAddrIndex;
this.handlerFuncParamIndex = handlerFuncIndex;
this.handlerAttachParamIndex = handlerAttachIndex;
this.paramAttrs = hasattr ? atts : null; this.paramAttrs = hasattr ? atts : null;
if (this.handlerFuncParamIndex >= 0 && method.getReturnType() != void.class) {
throw new RuntimeException(method + " have AsyncHandler type parameter but return type is not void");
}
} }
@Override @Override
@@ -126,19 +162,22 @@ public final class SncpClient {
protected final Consumer<Runnable> executor; protected final Consumer<Runnable> executor;
public <T extends Service> SncpClient(final String serviceName, final Class<T> serviceType, final T service, final Consumer<Runnable> executor, public <T extends Service> SncpClient(final String serviceName, final Class<T> serviceTypeOrImplClass, final T service, final Consumer<Runnable> executor,
final boolean remote, final Class serviceClass, final InetSocketAddress clientAddress) { final boolean remote, final Class serviceClass, final InetSocketAddress clientAddress) {
this.remote = remote; this.remote = remote;
this.executor = executor; this.executor = executor;
this.serviceClass = serviceClass; this.serviceClass = serviceClass;
this.serviceversion = service.version(); this.serviceversion = 0;
this.clientAddress = clientAddress; this.clientAddress = clientAddress;
this.name = serviceName; this.name = serviceName;
this.serviceid = Sncp.hash(serviceType.getName() + ':' + serviceName); Class tn = serviceTypeOrImplClass;
ResourceType rt = (ResourceType) tn.getAnnotation(ResourceType.class);
if (rt != null && rt.value().length > 0) tn = rt.value()[0];
this.serviceid = Sncp.hash(tn.getName() + ':' + serviceName);
final List<SncpAction> methodens = new ArrayList<>(); final List<SncpAction> methodens = new ArrayList<>();
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
for (java.lang.reflect.Method method : parseMethod(serviceClass)) { for (java.lang.reflect.Method method : parseMethod(serviceClass)) {
methodens.add(new SncpAction(method, Sncp.hash(method))); methodens.add(new SncpAction(serviceClass, method, Sncp.hash(method)));
} }
this.actions = methodens.toArray(new SncpAction[methodens.size()]); this.actions = methodens.toArray(new SncpAction[methodens.size()]);
this.addrBytes = clientAddress == null ? new byte[4] : clientAddress.getAddress().getAddress(); this.addrBytes = clientAddress == null ? new byte[4] : clientAddress.getAddress().getAddress();
@@ -149,7 +188,7 @@ public final class SncpClient {
final List<SncpAction> actions = new ArrayList<>(); final List<SncpAction> actions = new ArrayList<>();
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
for (java.lang.reflect.Method method : parseMethod(serviceClass)) { for (java.lang.reflect.Method method : parseMethod(serviceClass)) {
actions.add(new SncpAction(method, Sncp.hash(method))); actions.add(new SncpAction(serviceClass, method, Sncp.hash(method)));
} }
return actions; return actions;
} }
@@ -193,7 +232,7 @@ public final class SncpClient {
if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue; if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue;
if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue; if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue;
if (method.getName().equals("init") || method.getName().equals("destroy")) continue; if (method.getName().equals("init") || method.getName().equals("destroy")) continue;
if (method.getName().equals("version") || method.getName().equals("name")) continue; //if (method.getName().equals("version") || method.getName().equals("name")) continue;
//if (onlySncpDyn && method.getAnnotation(SncpDyn.class) == null) continue; //if (onlySncpDyn && method.getAnnotation(SncpDyn.class) == null) continue;
DLong actionid = Sncp.hash(method); DLong actionid = Sncp.hash(method);
Method old = actionids.get(actionid); Method old = actionids.get(actionid);
@@ -221,13 +260,16 @@ public final class SncpClient {
} }
public void remoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) { public void remoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
if (transport == null) return;
final SncpAction action = actions[index]; final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (InetSocketAddress addr : transport.getRemoteAddresses()) { for (InetSocketAddress addr : transport.getRemoteAddresses()) {
remote0(bsonConvert, jsonConvert, transport, addr, action, params); remote0(null, bsonConvert, jsonConvert, transport, addr, action, params);
} }
} }
public void asyncRemoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) { public void asyncRemoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
if (transport == null) return;
if (executor != null) { if (executor != null) {
executor.accept(() -> { executor.accept(() -> {
remoteSameGroup(bsonConvert, jsonConvert, transport, index, params); remoteSameGroup(bsonConvert, jsonConvert, transport, index, params);
@@ -240,8 +282,9 @@ public final class SncpClient {
public void remoteDiffGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport[] transports, final int index, final Object... params) { public void remoteDiffGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport[] transports, final int index, final Object... params) {
if (transports == null || transports.length < 1) return; if (transports == null || transports.length < 1) return;
final SncpAction action = actions[index]; final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (Transport transport : transports) { for (Transport transport : transports) {
remote0(bsonConvert, jsonConvert, transport, null, action, params); remote0(null, bsonConvert, jsonConvert, transport, null, action, params);
} }
} }
@@ -259,9 +302,34 @@ public final class SncpClient {
//只给远程模式调用的 //只给远程模式调用的
public <T> T remote(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) { public <T> T remote(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
final SncpAction action = actions[index]; final SncpAction action = actions[index];
SncpFuture<byte[]> future = remote0(bsonConvert, jsonConvert, transport, null, action, params); final AsyncHandler handlerFunc = action.handlerFuncParamIndex >= 0 ? (AsyncHandler) params[action.handlerFuncParamIndex] : null;
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null;
final BsonReader reader = bsonConvert.pollBsonReader(); final BsonReader reader = bsonConvert.pollBsonReader();
CompletableFuture<byte[]> future = remote0(handlerFunc, bsonConvert, jsonConvert, transport, null, action, params);
if (action.boolReturnTypeFuture) {
CompletableFuture result = action.futureCreator.create();
future.whenComplete((v, e) -> {
try {
if (e != null) {
result.completeExceptionally(e);
} else {
reader.setBytes(v);
byte i;
while ((i = reader.readByte()) != 0) {
final Attribute attr = action.paramAttrs[i];
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
}
Object rs = bsonConvert.convertFrom(Object.class, reader);
result.complete(rs);
}
} finally {
bsonConvert.offerBsonReader(reader);
}
}); //需要获取 Executor
return (T) result;
}
if (handlerFunc != null) return null;
try { try {
reader.setBytes(future.get(5, TimeUnit.SECONDS)); reader.setBytes(future.get(5, TimeUnit.SECONDS));
byte i; byte i;
@@ -269,7 +337,7 @@ public final class SncpClient {
final Attribute attr = action.paramAttrs[i]; final Attribute attr = action.paramAttrs[i];
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader)); attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
} }
return bsonConvert.convertFrom(action.resultTypes, reader); return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
} catch (InterruptedException | ExecutionException | TimeoutException e) { } catch (InterruptedException | ExecutionException | TimeoutException e) {
logger.log(Level.SEVERE, actions[index].method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote error", e); logger.log(Level.SEVERE, actions[index].method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote error", e);
throw new RuntimeException(actions[index].method + " sncp remote error", e); throw new RuntimeException(actions[index].method + " sncp remote error", e);
@@ -282,28 +350,30 @@ public final class SncpClient {
if (transports == null || transports.length < 1) return; if (transports == null || transports.length < 1) return;
remote(bsonConvert, jsonConvert, transports[0], index, params); remote(bsonConvert, jsonConvert, transports[0], index, params);
for (int i = 1; i < transports.length; i++) { for (int i = 1; i < transports.length; i++) {
remote0(bsonConvert, jsonConvert, transports[i], null, actions[index], params); remote0(null, bsonConvert, jsonConvert, transports[i], null, actions[index], params);
} }
} }
private SncpFuture<byte[]> remote0(final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { private CompletableFuture<byte[]> remote0(final AsyncHandler handler, final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
if ("rest".equalsIgnoreCase(transport.getKind())) { if ("rest".equalsIgnoreCase(transport.getSubprotocol())) {
return remoteRest0(jsonConvert, transport, addr0, action, params); return remoteRest0(handler, jsonConvert, transport, addr0, action, params);
} }
return remoteSncp0(bsonConvert, transport, addr0, action, params); return remoteSncp0(handler, bsonConvert, transport, addr0, action, params);
} }
private SncpFuture<byte[]> remoteRest0(final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { //尚未实现
private CompletableFuture<byte[]> remoteRest0(final AsyncHandler handler, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
return null; return null;
} }
private SncpFuture<byte[]> remoteSncp0(final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { private CompletableFuture<byte[]> remoteSncp0(final AsyncHandler handler, final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
Type[] myparamtypes = action.paramTypes; final Type[] myparamtypes = action.paramTypes;
final Class[] myparamclass = action.paramClass;
if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.clientAddress; if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.clientAddress;
final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入 final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
writer.writeTo(DEFAULT_HEADER); writer.writeTo(DEFAULT_HEADER);
for (int i = 0; i < params.length; i++) { for (int i = 0; i < params.length; i++) { //params 可能包含: 3 个 boolean
bsonConvert.convertTo(writer, myparamtypes[i], params[i]); bsonConvert.convertTo(writer, AsyncHandler.class.isAssignableFrom(myparamclass[i]) ? AsyncHandler.class : myparamtypes[i], params[i]);
} }
final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度 final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度
final long seqid = System.nanoTime(); final long seqid = System.nanoTime();
@@ -318,7 +388,7 @@ public final class SncpClient {
fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength); fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength);
final ByteBuffer buffer = transport.pollBuffer(); final ByteBuffer buffer = transport.pollBuffer();
final SncpFuture<byte[]> future = new SncpFuture(false); final CompletableFuture<byte[]> future = new CompletableFuture();
conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() { conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() {
@Override @Override
@@ -352,7 +422,7 @@ public final class SncpClient {
@Override @Override
public void completed(Integer count, Void attachment2) { public void completed(Integer count, Void attachment2) {
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读 if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
future.set(new RuntimeException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data")); future.completeExceptionally(new RuntimeException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
transport.offerBuffer(buffer); transport.offerBuffer(buffer);
transport.offerConnection(true, conn); transport.offerConnection(true, conn);
return; return;
@@ -397,17 +467,39 @@ public final class SncpClient {
} }
public void success() { public void success() {
future.set(this.body); future.complete(this.body);
transport.offerBuffer(buffer); transport.offerBuffer(buffer);
transport.offerConnection(false, conn); transport.offerConnection(false, conn);
if (handler != null) {
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
final BsonReader reader = bsonConvert.pollBsonReader();
try {
reader.setBytes(this.body);
int i;
while ((i = (reader.readByte() & 0xff)) != 0) {
final Attribute attr = action.paramAttrs[i];
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
}
Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
handler.completed(rs, handlerAttach);
} catch (Exception e) {
handler.failed(e, handlerAttach);
} finally {
bsonConvert.offerBsonReader(reader);
}
}
} }
@Override @Override
public void failed(Throwable exc, Void attachment2) { public void failed(Throwable exc, Void attachment2) {
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote read exec failed", exc); logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote read exec failed", exc);
future.set(new RuntimeException(action.method + " sncp remote exec failed")); future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
transport.offerBuffer(buffer); transport.offerBuffer(buffer);
transport.offerConnection(true, conn); transport.offerConnection(true, conn);
if (handler != null) {
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
handler.failed(exc, handlerAttach);
}
} }
}); });
} }
@@ -431,7 +523,8 @@ public final class SncpClient {
int version = buffer.getInt(); int version = buffer.getInt();
if (version != this.serviceversion) throw new RuntimeException("sncp(" + action.method + ") response.serviceversion = " + serviceversion + ", but request.serviceversion =" + version); if (version != this.serviceversion) throw new RuntimeException("sncp(" + action.method + ") response.serviceversion = " + serviceversion + ", but request.serviceversion =" + version);
DLong raction = DLong.read(buffer); DLong raction = DLong.read(buffer);
if (!action.actionid.equals(raction)) throw new RuntimeException("sncp(" + action.method + ") response.actionid = " + action.actionid + ", but request.actionid =(" + raction + ")"); DLong actid = action.actionid;
if (!actid.equals(raction)) throw new RuntimeException("sncp(" + action.method + ") response.actionid = " + action.actionid + ", but request.actionid =(" + raction + ")");
buffer.getInt(); //地址 buffer.getInt(); //地址
buffer.getChar(); //端口 buffer.getChar(); //端口
} }
@@ -452,91 +545,4 @@ public final class SncpClient {
buffer.position(currentpos); buffer.position(currentpos);
} }
protected static final class SncpFuture<T> implements Future<T> {
private volatile boolean done;
private T result;
private RuntimeException ex;
private final boolean rest;
public SncpFuture(boolean rest) {
this.rest = rest;
}
public SncpFuture(boolean rest, T result) {
this.rest = rest;
this.result = result;
this.done = true;
}
public boolean isRest() {
return this.rest;
}
public void set(T result) {
this.result = result;
this.done = true;
synchronized (this) {
notifyAll();
}
}
public void set(RuntimeException ex) {
this.ex = ex;
this.done = true;
synchronized (this) {
notifyAll();
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return done;
}
@Override
public T get() throws InterruptedException, ExecutionException {
if (done) {
if (ex != null) throw ex;
return result;
}
synchronized (this) {
if (!done) wait(10_000);
}
if (done) {
if (ex != null) throw ex;
return result;
}
throw new InterruptedException();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (done) {
if (ex != null) throw ex;
return result;
}
synchronized (this) {
if (!done) wait(unit.toMillis(timeout));
}
if (done) {
if (ex != null) throw ex;
return result;
}
throw new TimeoutException();
}
}
} }

View File

@@ -11,6 +11,7 @@ import java.lang.annotation.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.nio.*; import java.nio.*;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.*; import java.util.function.*;
import java.util.logging.*; import java.util.logging.*;
import javax.annotation.*; import javax.annotation.*;
@@ -19,6 +20,7 @@ import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.internal.org.objectweb.asm.Opcodes.*;
import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.Type;
import org.redkale.convert.bson.*; import org.redkale.convert.bson.*;
import org.redkale.net.sncp.SncpAsyncHandler.DefaultSncpAsyncHandler;
import org.redkale.service.*; import org.redkale.service.*;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.service.RpcCall; import org.redkale.service.RpcCall;
@@ -63,7 +65,7 @@ public final class SncpDynServlet extends SncpServlet {
if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue; if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue;
if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue; if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue;
if (method.getName().equals("init") || method.getName().equals("destroy")) continue; if (method.getName().equals("init") || method.getName().equals("destroy")) continue;
if (method.getName().equals("version") || method.getName().equals("name")) continue; //if (method.getName().equals("version") || method.getName().equals("name")) continue;
final DLong actionid = Sncp.hash(method); final DLong actionid = Sncp.hash(method);
SncpServletAction action = SncpServletAction.create(service, actionid, method); SncpServletAction action = SncpServletAction.create(service, actionid, method);
action.convert = convert; action.convert = convert;
@@ -80,7 +82,7 @@ public final class SncpDynServlet extends SncpServlet {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName()).append("(type=").append(type.getName()); sb.append(this.getClass().getSimpleName()).append(" (type=").append(type.getName());
int len = maxClassNameLength - type.getName().length(); int len = maxClassNameLength - type.getName().length();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
sb.append(' '); sb.append(' ');
@@ -112,7 +114,7 @@ public final class SncpDynServlet extends SncpServlet {
if (bufferSupplier == null) { if (bufferSupplier == null) {
bufferSupplier = request.getContext().getBufferSupplier(); bufferSupplier = request.getContext().getBufferSupplier();
} }
SncpServletAction action = actions.get(request.getActionid()); final SncpServletAction action = actions.get(request.getActionid());
//if (finest) logger.log(Level.FINEST, "sncpdyn.execute: " + request + ", " + (action == null ? "null" : action.method)); //if (finest) logger.log(Level.FINEST, "sncpdyn.execute: " + request + ", " + (action == null ? "null" : action.method));
if (action == null) { if (action == null) {
response.finish(SncpResponse.RETCODE_ILLACTIONID, null); //无效actionid response.finish(SncpResponse.RETCODE_ILLACTIONID, null); //无效actionid
@@ -120,16 +122,52 @@ public final class SncpDynServlet extends SncpServlet {
BsonWriter out = action.convert.pollBsonWriter(bufferSupplier); BsonWriter out = action.convert.pollBsonWriter(bufferSupplier);
out.writeTo(DEFAULT_HEADER); out.writeTo(DEFAULT_HEADER);
BsonReader in = action.convert.pollBsonReader(); BsonReader in = action.convert.pollBsonReader();
SncpAsyncHandler handler = null;
try { try {
if (action.handlerFuncParamIndex >= 0) {
if (action.handlerFuncParamClass == AsyncHandler.class) {
handler = new DefaultSncpAsyncHandler(action, in, out, request, response);
} else {
Creator<SncpAsyncHandler> creator = action.handlerCreator;
if (creator == null) {
creator = SncpAsyncHandler.Factory.createCreator(action.handlerFuncParamClass);
action.handlerCreator = creator;
}
handler = creator.create(new DefaultSncpAsyncHandler(action, in, out, request, response));
}
} else if (action.boolReturnTypeFuture) {
handler = new DefaultSncpAsyncHandler(action, in, out, request, response);
}
in.setBytes(request.getBody()); in.setBytes(request.getBody());
action.action(in, out); action.action(in, out, handler);
response.finish(0, out); if (handler == null) {
response.finish(0, out);
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
} else if (action.boolReturnTypeFuture) {
CompletableFuture future = handler.sncp_getFuture();
if (future == null) {
action._callParameter(out, handler.sncp_getParams());
action.convert.convertTo(out, Object.class, null);
} else {
Object[] sncpParams = handler.sncp_getParams();
future.whenComplete((v, e) -> {
if (e != null) {
response.getContext().getLogger().log(Level.INFO, "sncp CompleteAsync error(" + request + ")", e);
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
return;
}
action._callParameter(out, sncpParams);
action.convert.convertTo(out, Object.class, v);
response.finish(0, out);
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
});
}
}
} catch (Throwable t) { } catch (Throwable t) {
response.getContext().getLogger().log(Level.INFO, "sncp execute error(" + request + ")", t); response.getContext().getLogger().log(Level.INFO, "sncp execute error(" + request + ")", t);
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null); response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
} finally {
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
} }
} }
} }
@@ -138,6 +176,8 @@ public final class SncpDynServlet extends SncpServlet {
public Method method; public Method method;
public Creator<SncpAsyncHandler> handlerCreator;
@Resource @Resource
protected BsonConvert convert; protected BsonConvert convert;
@@ -145,8 +185,15 @@ public final class SncpDynServlet extends SncpServlet {
protected java.lang.reflect.Type[] paramTypes; //index=0表示返回参数的type void的返回参数类型为null protected java.lang.reflect.Type[] paramTypes; //index=0表示返回参数的type void的返回参数类型为null
public abstract void action(final BsonReader in, final BsonWriter out) throws Throwable; protected int handlerFuncParamIndex = -1; //handlerFuncParamIndex>=0表示存在AsyncHandler参数
protected boolean boolReturnTypeFuture = false; // 返回结果类型是否为 CompletableFuture
protected Class handlerFuncParamClass; //AsyncHandler参数的类型
public abstract void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable;
//只有同步方法才调用 (没有AsyncHandler、CompletableFuture)
public final void _callParameter(final BsonWriter out, final Object... params) { public final void _callParameter(final BsonWriter out, final Object... params) {
if (paramAttrs != null) { if (paramAttrs != null) {
for (int i = 1; i < paramAttrs.length; i++) { for (int i = 1; i < paramAttrs.length; i++) {
@@ -162,17 +209,29 @@ public final class SncpDynServlet extends SncpServlet {
/** /**
* <blockquote><pre> * <blockquote><pre>
* public class TestService implements Service { * public class TestService implements Service {
*
* public boolean change(TestBean bean, String name, int id) { * public boolean change(TestBean bean, String name, int id) {
* * return false;
* } * }
* }
* *
* public class DynActionTestService_change extends SncpServletAction { * public void insert(AsyncHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id) {
* }
*
* public void update(long show, short v2, AsyncHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id) {
* }
*
* public CompletableFuture&#60;String&#62; changeName(TestBean bean, String name, int id) {
* return null;
* }
* }
*
*
* class DynActionTestService_change extends SncpServletAction {
* *
* public TestService service; * public TestService service;
* *
* &#64;Override * &#064;Override
* public void action(final BsonReader in, final BsonWriter out) throws Throwable { * public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
* TestBean arg1 = convert.convertFrom(paramTypes[1], in); * TestBean arg1 = convert.convertFrom(paramTypes[1], in);
* String arg2 = convert.convertFrom(paramTypes[2], in); * String arg2 = convert.convertFrom(paramTypes[2], in);
* int arg3 = convert.convertFrom(paramTypes[3], in); * int arg3 = convert.convertFrom(paramTypes[3], in);
@@ -180,7 +239,58 @@ public final class SncpDynServlet extends SncpServlet {
* _callParameter(out, arg1, arg2, arg3); * _callParameter(out, arg1, arg2, arg3);
* convert.convertTo(out, paramTypes[0], rs); * convert.convertTo(out, paramTypes[0], rs);
* } * }
* } * }
*
* class DynActionTestService_insert extends SncpServletAction {
*
* public TestService service;
*
* &#064;Override
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
* SncpAsyncHandler arg0 = handler;
* convert.convertFrom(AsyncHandler.class, in);
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
* String arg2 = convert.convertFrom(paramTypes[3], in);
* int arg3 = convert.convertFrom(paramTypes[4], in);
* handler.sncp_setParams(arg0, arg1, arg2, arg3);
* service.insert(arg0, arg1, arg2, arg3);
* }
* }
*
* class DynActionTestService_update extends SncpServletAction {
*
* public TestService service;
*
* &#064;Override
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
* long a1 = convert.convertFrom(paramTypes[1], in);
* short a2 = convert.convertFrom(paramTypes[2], in);
* SncpAsyncHandler a3 = handler;
* convert.convertFrom(AsyncHandler.class, in);
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
* String arg2 = convert.convertFrom(paramTypes[5], in);
* int arg3 = convert.convertFrom(paramTypes[6], in);
* handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
* service.update(a1, a2, a3, arg1, arg2, arg3);
* }
* }
*
*
* class DynActionTestService_changeName extends SncpServletAction {
*
* public TestService service;
*
* &#064;Override
* public void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable {
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
* String arg2 = convert.convertFrom(paramTypes[2], in);
* int arg3 = convert.convertFrom(paramTypes[3], in);
* handler.sncp_setParams(arg1, arg2, arg3);
* CompletableFuture future = service.changeName(arg1, arg2, arg3);
* handler.sncp_setFuture(future);
* }
* }
*
* </pre></blockquote> * </pre></blockquote>
* *
* @param service Service * @param service Service
@@ -195,16 +305,19 @@ public final class SncpDynServlet extends SncpServlet {
final String supDynName = SncpServletAction.class.getName().replace('.', '/'); final String supDynName = SncpServletAction.class.getName().replace('.', '/');
final String serviceName = serviceClass.getName().replace('.', '/'); final String serviceName = serviceClass.getName().replace('.', '/');
final String convertName = BsonConvert.class.getName().replace('.', '/'); final String convertName = BsonConvert.class.getName().replace('.', '/');
final String handlerName = SncpAsyncHandler.class.getName().replace('.', '/');
final String asyncHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class);
final String convertReaderDesc = Type.getDescriptor(BsonReader.class); final String convertReaderDesc = Type.getDescriptor(BsonReader.class);
final String convertWriterDesc = Type.getDescriptor(BsonWriter.class); final String convertWriterDesc = Type.getDescriptor(BsonWriter.class);
final String serviceDesc = Type.getDescriptor(serviceClass); final String serviceDesc = Type.getDescriptor(serviceClass);
final boolean boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
String newDynName = serviceName.substring(0, serviceName.lastIndexOf('/') + 1) String newDynName = serviceName.substring(0, serviceName.lastIndexOf('/') + 1)
+ "DynAction" + serviceClass.getSimpleName() + "_" + method.getName() + "_" + actionid; + "DynAction" + serviceClass.getSimpleName() + "_" + method.getName() + "_" + actionid;
while (true) { while (true) {
try { try {
Class.forName(newDynName.replace('/', '.')); Class.forName(newDynName.replace('/', '.'));
newDynName += "_"; newDynName += "_";
} catch (Exception ex) { } catch (Throwable ex) {
break; break;
} }
} }
@@ -236,15 +349,42 @@ public final class SncpDynServlet extends SncpServlet {
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException(ex); //不可能会发生 throw new RuntimeException(ex); //不可能会发生
} }
int handlerFuncIndex = -1;
Class handlerFuncClass = null;
{ // action方法 { // action方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + ")V", null, new String[]{"java/lang/Throwable"})); mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + asyncHandlerDesc + ")V", null, new String[]{"java/lang/Throwable"}));
//mv.setDebug(true); //mv.setDebug(true);
int iconst = ICONST_1; int iconst = ICONST_1;
int intconst = 1; int intconst = 1;
int store = 3; //action的参数个数+1 int store = 4; //action的参数个数+1
final Class[] paramClasses = method.getParameterTypes(); final Class[] paramClasses = method.getParameterTypes();
int[][] codes = new int[paramClasses.length][2]; int[][] codes = new int[paramClasses.length][2];
for (int i = 0; i < paramClasses.length; i++) { //参数 for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数
if (AsyncHandler.class.isAssignableFrom(paramClasses[i])) {
if (boolReturnTypeFuture) {
throw new RuntimeException(method + " have both AsyncHandler and CompletableFuture");
}
if (handlerFuncIndex >= 0) {
throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
}
Sncp.checkAsyncModifier(paramClasses[i], method);
handlerFuncIndex = i;
handlerFuncClass = paramClasses[i];
mv.visitVarInsn(ALOAD, 3);
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
mv.visitVarInsn(ASTORE, store);
codes[i] = new int[]{ALOAD, store};
store++;
iconst++;
intconst++;
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
mv.visitLdcInsn(Type.getType(Type.getDescriptor(AsyncHandler.class)));
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
mv.visitInsn(POP);
continue;
}
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
@@ -296,6 +436,43 @@ public final class SncpDynServlet extends SncpServlet {
intconst++; intconst++;
store++; store++;
} }
if (boolReturnTypeFuture || handlerFuncIndex >= 0) { //调用SncpAsyncHandler.setParams(Object... params)
mv.visitVarInsn(ALOAD, 3);
if (paramClasses.length > 5) {
mv.visitIntInsn(BIPUSH, paramClasses.length);
} else {
mv.visitInsn(paramClasses.length + ICONST_0);
}
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int insn = 3; //action的参数个数
for (int j = 0; j < paramClasses.length; j++) {
final Class pt = paramClasses[j];
mv.visitInsn(DUP);
insn++;
if (j <= 5) {
mv.visitInsn(ICONST_0 + j);
} else {
mv.visitIntInsn(BIPUSH, j);
}
if (pt.isPrimitive()) {
if (pt == long.class) {
mv.visitVarInsn(LLOAD, insn++);
} else if (pt == float.class) {
mv.visitVarInsn(FLOAD, insn++);
} else if (pt == double.class) {
mv.visitVarInsn(DLOAD, insn++);
} else {
mv.visitVarInsn(ILOAD, insn);
}
Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(pt, 1), 0).getClass();
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
} else {
mv.visitVarInsn(ALOAD, insn);
}
mv.visitInsn(AASTORE);
}
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
}
{ //调用service { //调用service
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "service", serviceDesc); mv.visitFieldInsn(GETFIELD, newDynName, "service", serviceDesc);
@@ -317,51 +494,57 @@ public final class SncpDynServlet extends SncpServlet {
} }
} }
mv.visitVarInsn(ASTORE, store); //11 mv.visitVarInsn(ASTORE, store); //11
} if (boolReturnTypeFuture) {
//------------------------- _callParameter 方法 -------------------------------- mv.visitVarInsn(ALOAD, 3);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, store);
mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setFuture", "(Ljava/util/concurrent/CompletableFuture;)V", true);
if (paramClasses.length <= 5) { //参数总数量
mv.visitInsn(ICONST_0 + paramClasses.length);
} else {
mv.visitIntInsn(BIPUSH, paramClasses.length);
}
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int insn = 2;
for (int j = 0; j < paramClasses.length; j++) {
final Class pt = paramClasses[j];
mv.visitInsn(DUP);
insn++;
if (j <= 5) {
mv.visitInsn(ICONST_0 + j);
} else {
mv.visitIntInsn(BIPUSH, j);
} }
if (pt.isPrimitive()) { }
if (pt == long.class) { if (!boolReturnTypeFuture && handlerFuncIndex < 0) { //同步方法
mv.visitVarInsn(LLOAD, insn++); //------------------------- _callParameter 方法 --------------------------------
} else if (pt == float.class) { mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(FLOAD, insn++); mv.visitVarInsn(ALOAD, 2);
} else if (pt == double.class) { if (paramClasses.length <= 5) { //参数总数量
mv.visitVarInsn(DLOAD, insn++); mv.visitInsn(ICONST_0 + paramClasses.length);
} else {
mv.visitIntInsn(BIPUSH, paramClasses.length);
}
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int insn = 3;//action的参数个数
for (int j = 0; j < paramClasses.length; j++) {
final Class pt = paramClasses[j];
mv.visitInsn(DUP);
insn++;
if (j <= 5) {
mv.visitInsn(ICONST_0 + j);
} else { } else {
mv.visitVarInsn(ILOAD, insn); mv.visitIntInsn(BIPUSH, j);
} }
Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(pt, 1), 0).getClass(); if (pt.isPrimitive()) {
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false); if (pt == long.class) {
} else { mv.visitVarInsn(LLOAD, insn++);
mv.visitVarInsn(ALOAD, insn); } else if (pt == float.class) {
mv.visitVarInsn(FLOAD, insn++);
} else if (pt == double.class) {
mv.visitVarInsn(DLOAD, insn++);
} else {
mv.visitVarInsn(ILOAD, insn);
}
Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(pt, 1), 0).getClass();
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
} else {
mv.visitVarInsn(ALOAD, insn);
}
mv.visitInsn(AASTORE);
} }
mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false);
} }
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false);
//-------------------------直接返回 或者 调用convertTo方法 -------------------------------- //-------------------------直接返回 或者 调用convertTo方法 --------------------------------
int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1; int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1;
if (returnClass == void.class) { //返回 if (boolReturnTypeFuture || returnClass == void.class) { //返回
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxStack = 8; maxStack = 8;
} else { } else { //同步方法调用
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class)); mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
@@ -398,6 +581,9 @@ public final class SncpDynServlet extends SncpServlet {
types[0] = rt; types[0] = rt;
System.arraycopy(ptypes, 0, types, 1, ptypes.length); System.arraycopy(ptypes, 0, types, 1, ptypes.length);
instance.paramTypes = types; instance.paramTypes = types;
instance.handlerFuncParamIndex = handlerFuncIndex;
instance.handlerFuncParamClass = handlerFuncClass;
instance.boolReturnTypeFuture = boolReturnTypeFuture;
org.redkale.util.Attribute[] atts = new org.redkale.util.Attribute[ptypes.length + 1]; org.redkale.util.Attribute[] atts = new org.redkale.util.Attribute[ptypes.length + 1];
Annotation[][] anns = method.getParameterAnnotations(); Annotation[][] anns = method.getParameterAnnotations();

View File

@@ -30,26 +30,22 @@ public class SncpPrepareServlet extends PrepareServlet<DLong, SncpContext, SncpR
public void addServlet(SncpServlet servlet, AnyValue conf) { public void addServlet(SncpServlet servlet, AnyValue conf) {
setServletConf(servlet, conf); setServletConf(servlet, conf);
synchronized (mappings) { putMapping(servlet.getServiceid(), servlet);
mappings.put(servlet.getServiceid(), servlet); putServlet(servlet);
servlets.add(servlet);
}
} }
public List<SncpServlet> getSncpServlets() { public List<SncpServlet> getSncpServlets() {
ArrayList<SncpServlet> list = new ArrayList<>(servlets.size()); return new ArrayList<>(getServlets());
servlets.forEach(x -> list.add((SncpServlet) x));
return list;
} }
@Override @Override
public void init(SncpContext context, AnyValue config) { public void init(SncpContext context, AnyValue config) {
servlets.forEach(s -> s.init(context, getServletConf(s))); getServlets().forEach(s -> s.init(context, getServletConf(s)));
} }
@Override @Override
public void destroy(SncpContext context, AnyValue config) { public void destroy(SncpContext context, AnyValue config) {
servlets.forEach(s -> s.destroy(context, getServletConf(s))); getServlets().forEach(s -> s.destroy(context, getServletConf(s)));
} }
@Override @Override
@@ -58,7 +54,7 @@ public class SncpPrepareServlet extends PrepareServlet<DLong, SncpContext, SncpR
response.finish(pongBuffer.duplicate()); response.finish(pongBuffer.duplicate());
return; return;
} }
SncpServlet servlet = (SncpServlet) mappings.get(request.getServiceid()); SncpServlet servlet = (SncpServlet) mappingServlet(request.getServiceid());
if (servlet == null) { if (servlet == null) {
response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); //无效serviceid response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); //无效serviceid
} else { } else {

View File

@@ -38,15 +38,15 @@ public final class SncpServer extends Server<DLong, SncpContext, SncpRequest, Sn
super.init(config); super.init(config);
} }
public void addSncpServlet(ServiceWrapper entry) { public void addSncpServlet(Service sncpService) {
for (Class type : entry.getTypes()) { for (Class type : Sncp.getResourceTypes(sncpService)) {
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), entry.getName(), type, entry.getService()); SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), Sncp.getResourceName(sncpService), type, sncpService);
this.prepare.addServlet(sds, null, entry.getConf()); this.prepare.addServlet(sds, null, Sncp.getConf(sncpService));
} }
} }
public <T extends Service> void addSncpServlet(Class<T> serviceType, String name, T service, AnyValue conf) { public <T extends Service> void addSncpServlet(Class<T> serviceTypeClass, String name, T service, AnyValue conf) {
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), name, serviceType, service); SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), name, serviceTypeClass, service);
this.prepare.addServlet(sds, null, conf); this.prepare.addServlet(sds, null, conf);
} }

View File

@@ -6,6 +6,7 @@
package org.redkale.net.sncp; package org.redkale.net.sncp;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.*;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.util.*; import org.redkale.util.*;
@@ -20,6 +21,14 @@ public abstract class SncpServlet extends Servlet<SncpContext, SncpRequest, Sncp
public abstract DLong getServiceid(); public abstract DLong getServiceid();
protected ExecutorService getExecutor() {
Thread thread = Thread.currentThread();
if (thread instanceof WorkThread) {
return ((WorkThread) thread).getExecutor();
}
return ForkJoinPool.commonPool();
}
@Override @Override
public final boolean equals(Object obj) { public final boolean equals(Object obj) {
if (!(obj instanceof SncpServlet)) return false; if (!(obj instanceof SncpServlet)) return false;

View File

@@ -0,0 +1,33 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.service;
import java.util.concurrent.*;
import org.redkale.net.WorkThread;
/**
*
* @author zhangjx
*/
public abstract class AbstractService implements Service {
protected void runAsync(Runnable runner) {
Thread thread = Thread.currentThread();
if (thread instanceof WorkThread) {
((WorkThread) thread).runAsync(runner);
} else {
ForkJoinPool.commonPool().execute(runner);
}
}
protected ExecutorService getExecutor() {
Thread thread = Thread.currentThread();
if (thread instanceof WorkThread) {
return ((WorkThread) thread).getExecutor();
}
return ForkJoinPool.commonPool();
}
}

View File

@@ -11,6 +11,7 @@ import org.redkale.source.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 实现进程间DataSource的缓存数据同步
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -26,20 +27,23 @@ public class DataCacheListenerService implements DataCacheListener, Service {
@Override @Override
@RpcMultiRun(selfrun = false, async = true) @RpcMultiRun(selfrun = false, async = true)
public <T> void insertCache(Class<T> clazz, T... entitys) { public <T> int insertCache(Class<T> clazz, T... entitys) {
((DataDefaultSource) source).insertCache(clazz, entitys); if (!(source instanceof DataCacheListener)) return -2;
return ((DataCacheListener) source).insertCache(clazz, entitys);
} }
@Override @Override
@RpcMultiRun(selfrun = false, async = true) @RpcMultiRun(selfrun = false, async = true)
public <T> void updateCache(Class<T> clazz, T... entitys) { public <T> int updateCache(Class<T> clazz, T... entitys) {
((DataDefaultSource) source).updateCache(clazz, entitys); if (!(source instanceof DataCacheListener)) return -2;
return ((DataCacheListener) source).updateCache(clazz, entitys);
} }
@Override @Override
@RpcMultiRun(selfrun = false, async = true) @RpcMultiRun(selfrun = false, async = true)
public <T> void deleteCache(Class<T> clazz, Serializable... ids) { public <T> int deleteCache(Class<T> clazz, Serializable... ids) {
((DataDefaultSource) source).deleteCache(clazz, ids); if (!(source instanceof DataCacheListener)) return -2;
return ((DataCacheListener) source).deleteCache(clazz, ids);
} }
} }

View File

@@ -1,306 +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.service;
import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.function.*;
import javax.annotation.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* DataSource对应的Service类 该类主要特点是将所有含FilterBean参数的方法重载成FilterNode对应的方法。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@AutoLoad(false)
@ResourceType({DataSourceService.class, DataSource.class})
public class DataSourceService implements DataSource, Service, AutoCloseable {
@Resource(name = "$")
private DataSource source;
@Override
public <T> void insert(@RpcCall(DataCallArrayAttribute.class) T... values) {
source.insert(values);
}
@Override
public <T> int delete(T... values) {
return source.delete(values);
}
@Override
public <T> int delete(final Class<T> clazz, final Serializable... ids) {
return source.delete(clazz, ids);
}
@Override
public <T> int delete(final Class<T> clazz, FilterNode node) {
return source.delete(clazz, node);
}
@Override
public <T> int update(T... values) {
return source.update(values);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value) {
return source.updateColumn(clazz, id, column, value);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node) {
return source.updateColumn(clazz, column, value, node);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
return source.updateColumn(clazz, id, values);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
return source.updateColumn(clazz, node, values);
}
@Override
public <T> int updateColumns(T bean, final String... columns) {
return source.updateColumns(bean, columns);
}
@Override
public <T> int updateColumns(T bean, final FilterNode node, final String... columns) {
return source.updateColumns(bean, node, columns);
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final String column) {
return source.getNumberResult(entityClass, func, column);
}
@Override
public final Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean));
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterNode node) {
return source.getNumberResult(entityClass, func, column, node);
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column) {
return source.getNumberResult(entityClass, func, defVal, column);
}
@Override
public final Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean));
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterNode node) {
return source.getNumberResult(entityClass, func, defVal, column, node);
}
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn) {
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn);
}
@Override
public final <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterBean bean) {
return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterNode node) {
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
}
@Override
public <T> T find(final Class<T> clazz, final Serializable pk) {
return source.find(clazz, pk);
}
@Override
public <T> T find(final Class<T> clazz, SelectColumn selects, final Serializable pk) {
return source.find(clazz, selects, pk);
}
@Override
public <T> T find(final Class<T> clazz, final String column, final Serializable key) {
return source.find(clazz, column, key);
}
@Override
public final <T> T find(final Class<T> clazz, FilterBean bean) {
return find(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> T find(final Class<T> clazz, FilterNode node) {
return source.find(clazz, node);
}
@Override
public final <T> T find(final Class<T> clazz, final SelectColumn selects, FilterBean bean) {
return find(clazz, selects, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
return source.find(clazz, selects, node);
}
@Override
public <T> boolean exists(final Class<T> clazz, final Serializable pk) {
return source.exists(clazz, pk);
}
@Override
public final <T> boolean exists(final Class<T> clazz, FilterBean bean) {
return exists(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> boolean exists(final Class<T> clazz, FilterNode node) {
return source.exists(clazz, node);
}
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, final String column, final Serializable key) {
return source.queryColumnSet(selectedColumn, clazz, column, key);
}
@Override
public final <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterBean bean) {
return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterNode node) {
return source.queryColumnSet(selectedColumn, clazz, node);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, final String column, final Serializable key) {
return source.queryColumnList(selectedColumn, clazz, column, key);
}
@Override
public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterBean bean) {
return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterNode node) {
return source.queryColumnList(selectedColumn, clazz, node);
}
@Override
public final <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) {
return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) {
return source.queryColumnSheet(selectedColumn, clazz, flipper, node);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key) {
return source.queryList(clazz, column, key);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final FilterBean bean) {
return queryList(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final FilterNode node) {
return source.queryList(clazz, node);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
return queryList(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
return source.queryList(clazz, selects, node);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key) {
return source.queryList(clazz, flipper, column, key);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return queryList(clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return source.queryList(clazz, flipper, node);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return source.queryList(clazz, selects, flipper, node);
}
@Override
public final <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return querySheet(clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return source.querySheet(clazz, flipper, node);
}
@Override
public final <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return source.querySheet(clazz, selects, flipper, node);
}
@Override
public void close() throws Exception {
source.getClass().getMethod("close").invoke(source);
}
@Override
public final void directQuery(String sql, Consumer<ResultSet> consumer) {
source.directQuery(sql, consumer);
}
@Override
public final int[] directExecute(String... sqls) {
return source.directExecute(sqls);
}
}

View File

@@ -7,15 +7,16 @@ package org.redkale.service;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.text.MessageFormat;
import java.util.*; import java.util.*;
/** /**
* 用于定义错误码的注解 * 用于定义错误码的注解 <br>
* 结果码定义范围: * 结果码定义范围: <br>
* // 10000001 - 19999999 预留给Redkale的核心包使用 * // 10000001 - 19999999 预留给Redkale的核心包使用 <br>
* // 20000001 - 29999999 预留给Redkale的扩展包使用 * // 20000001 - 29999999 预留给Redkale的扩展包使用 <br>
* // 30000001 - 99999999 预留给Dev开发系统自身使用 * // 30000001 - 99999999 预留给Dev开发系统自身使用 <br>
* * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
@@ -28,6 +29,39 @@ public @interface RetLabel {
String value(); String value();
public static abstract class AbstractRetCode {
protected static final Map<Integer, String> rets = new HashMap();
protected static void load(Class clazz) {
rets.putAll(RetLoader.load(clazz));
}
public static RetResult retResult(int retcode) {
if (retcode == 0) return RetResult.success();
return new RetResult(retcode, retInfo(retcode));
}
public static RetResult retResult(int retcode, Object... args) {
if (retcode == 0) return RetResult.success();
if (args == null || args.length < 1) return new RetResult(retcode, retInfo(retcode));
String info = MessageFormat.format(retInfo(retcode), args);
return new RetResult(retcode, info);
}
public static RetResult set(RetResult result, int retcode, Object... args) {
if (retcode == 0) return result.retcode(0).retinfo("");
if (args == null || args.length < 1) return result.retcode(retcode).retinfo(retInfo(retcode));
String info = MessageFormat.format(retInfo(retcode), args);
return result.retcode(retcode).retinfo(info);
}
public static String retInfo(int retcode) {
if (retcode == 0) return "成功";
return rets.getOrDefault(retcode, "未知错误");
}
}
public static abstract class RetLoader { public static abstract class RetLoader {
public static Map<Integer, String> load(Class clazz) { public static Map<Integer, String> load(Class clazz) {

View File

@@ -8,13 +8,13 @@ package org.redkale.service;
import org.redkale.convert.json.*; import org.redkale.convert.json.*;
/** /**
* 通用的结果对象在常见的HTTP+JSON接口中返回的结果需要含结果码错误信息和实体对象。 * 通用的结果对象在常见的HTTP+JSON接口中返回的结果需要含结果码错误信息和实体对象。 <br>
* 通常前四位为模块,后四位为操作。 * 结果码定义通常前四位为模块,后四位为操作。<br>
* 结果码定义范围: * 结果码定义范围: <br>
* // 10000001 - 19999999 预留给Redkale的核心包使用 * // 10000001 - 19999999 预留给Redkale的核心包使用 <br>
* // 20000001 - 29999999 预留给Redkale的扩展包使用 * // 20000001 - 29999999 预留给Redkale的扩展包使用 <br>
* // 30000001 - 99999999 预留给Dev开发系统自身使用 * // 30000001 - 99999999 预留给Dev开发系统自身使用 <br>
* * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
@@ -22,13 +22,6 @@ import org.redkale.convert.json.*;
*/ */
public class RetResult<T> { public class RetResult<T> {
/**
* 使用 RetResult.success() 方法代替
*
* @deprecated
*/
private static final RetResult SUCCESS = new RetResult();
protected int retcode; protected int retcode;
protected String retinfo; protected String retinfo;
@@ -119,10 +112,20 @@ public class RetResult<T> {
this.retcode = retcode; this.retcode = retcode;
} }
/**
* 结果信息通常retcode != 0时值为错误信息
*
* @return 结果信息
*/
public String getRetinfo() { public String getRetinfo() {
return retinfo; return retinfo;
} }
/**
* 设置结果信息
*
* @param retinfo 结果信息
*/
public void setRetinfo(String retinfo) { public void setRetinfo(String retinfo) {
this.retinfo = retinfo; this.retinfo = retinfo;
} }
@@ -136,6 +139,11 @@ public class RetResult<T> {
return result; return result;
} }
/**
* 设置结果对象
*
* @param result T
*/
public void setResult(T result) { public void setResult(T result) {
this.result = result; this.result = result;
} }

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