558 Commits
1.4.0 ... 1.8.5

Author SHA1 Message Date
Redkale
500545fc93 DataSource.queryMap重载了FilterBean、FilterNode参数等系列方法 2017-10-30 09:49:34 +08:00
Redkale
78f1bd90f4 2017-10-27 16:42:01 +08:00
Redkale
f5a04319d5 2017-10-26 20:04:32 +08:00
Redkale
76ce6787d1 2017-10-26 14:48:15 +08:00
Redkale
bd53d4a8ab 2017-10-26 14:17:24 +08:00
Redkale
53b11116b9 DataSource增加queryMap系列方法 2017-10-26 13:20:05 +08:00
Redkale
734b1bbbb4 2017-10-26 10:23:43 +08:00
Redkale
f014bffb6c Redkale 1.8.5 开始 2017-10-25 09:51:08 +08:00
Redkale
f633e72c5f 2017-10-25 09:26:57 +08:00
Redkale
b8c85284ab 2017-10-25 09:21:48 +08:00
Redkale
a3af6749f6 暂时屏蔽Persist功能 2017-10-25 09:21:00 +08:00
Redkale
9128dffe35 新增Persist注解, 用于Service成员变量数据的临时缓存 2017-10-24 17:30:51 +08:00
Redkale
9273f2917e 2017-10-24 15:23:43 +08:00
Redkale
4d9d09af8c 2017-10-24 10:28:21 +08:00
Redkale
33beb60efe 2017-10-23 11:38:11 +08:00
Redkale
129bcf2f78 2017-10-22 16:01:20 +08:00
Redkale
f6c7dde28f Server增加setThreads方法,可以动态修改线程池的大小 2017-10-22 15:39:00 +08:00
Redkale
8fcd33b511 Copy一份javax.annotation.Resource源码到Redkale中,因JDK9中java.base模块中不包含javax.annotation.Resource 2017-10-22 13:01:03 +08:00
Redkale
66ec26e0ce 2017-10-22 11:14:49 +08:00
Redkale
969f7ada82 2017-10-22 11:04:00 +08:00
Redkale
7e37889372 增加Priority功能, 可以对Service、Filter、HttpServlet的加载顺序进行优先级设置,同时删掉Filter的getIndex方法 2017-10-22 11:00:09 +08:00
Redkale
c819d4d45b WATCH协议服务器默认host改为127.0.0.1 2017-10-22 10:13:24 +08:00
Redkale
6dc59b7abc 2017-10-21 11:07:16 +08:00
Redkale
60b24fa1ae 2017-10-20 10:58:31 +08:00
Redkale
b784993110 WebSocket的sendMessage系列方法增加Stream userids参数 2017-10-20 10:45:56 +08:00
Redkale
cc150a2cc6 @RestUploadFile标记的File对象可以获取到用户上传的文件名 2017-10-20 09:41:34 +08:00
Redkale
f6b407aa44 WebSocket识别Single模式,Single模式下重复登陆时默认会关闭之前的WebSocket连接 2017-10-18 10:47:43 +08:00
Redkale
a69d813bf5 WebSocket增加forceCloseWebSocket系列方法 2017-10-18 10:05:10 +08:00
Redkale
d1eff6144d convertMapTo方法识别CompletableFuture 2017-10-18 09:16:55 +08:00
Redkale
99589387d8 RetResult增加Map<String, String> attach成员变量 2017-10-17 09:42:32 +08:00
Redkale
e0041235fe WebSocket增加sendMap方法 2017-10-16 11:19:58 +08:00
Redkale
84b4eee7b5 重载WebSocket的sendMessage和broadcastMessage系列方法,增加Convert参数 2017-10-16 10:48:14 +08:00
Redkale
96c0a9bfe4 2017-10-15 22:22:31 +08:00
Redkale
89ad976744 增加BigDecimal的序列化和反序列化 2017-10-15 22:01:16 +08:00
Redkale
0eedc2c180 Redkale 1.8.4 开始 2017-10-15 21:59:59 +08:00
Redkale
8b3658143a 修复HttpResponse.finishFile传输偶尔异常的BUG 2017-09-25 11:40:49 +08:00
Redkale
6d69ff546b 2017-09-13 11:10:24 +08:00
Redkale
9555e3c9b9 2017-09-13 10:43:34 +08:00
Redkale
744634dbdd ResourceFactory 增加 public <A> List<A> query(final BiPredicate<String, A> predicate) 方法 2017-09-12 19:34:50 +08:00
Redkale
de5ee844c4 Convert 增加 convertMapTo 系列方法, HttpResponse增加 finishMapJson 系列方法 2017-09-09 22:36:35 +08:00
Redkale
ae73cee357 2017-09-09 13:24:19 +08:00
Redkale
d1cf9be8d7 AnyEncoder增加convertMapTo方法 2017-09-09 13:23:35 +08:00
Redkale
43ae77ab33 2017-09-01 11:13:22 +08:00
Redkale
182a75cfad 修复创建RestServlet时方法内含try/catch导致获取方法参数名错位的BUG 2017-09-01 10:51:41 +08:00
Redkale
222dc0edce 2017-08-28 21:54:48 +08:00
Redkale
c7a81513fe Redkale 1.8.3 开始 2017-08-28 19:20:51 +08:00
Redkale
4931c66868 2017-08-28 18:11:55 +08:00
Redkale
fcff1c3a4b 修复ByteBuffer的缓存区域会重复的BUG 2017-08-28 17:50:09 +08:00
Redkale
2005bf7e3b 2017-08-27 17:18:13 +08:00
Redkale
cb07a38f04 2017-08-27 14:37:06 +08:00
Redkale
6085cd5eef 2017-08-25 12:54:23 +08:00
Redkale
086275c135 2017-08-22 15:55:25 +08:00
Redkale
a449a96ef9 2017-08-22 15:10:17 +08:00
Redkale
bc3209a09c 2017-08-21 14:40:36 +08:00
Redkale
63d1ef985d 2017-08-18 14:48:21 +08:00
Redkale
24505564c8 2017-08-14 16:22:46 +08:00
Redkale
93a7bd63cf WebSocket 增加 onOccurException 方法 2017-08-12 07:56:42 +08:00
Redkale
0b9b5baa49 HTTP服务增加OPTIONS配置项功能 2017-08-10 16:19:58 +08:00
Redkale
5c4100e762 2017-08-10 15:05:46 +08:00
Redkale
eb861014c4 2017-08-10 10:24:37 +08:00
Redkale
e62f7ea63d 2017-08-06 12:25:56 +08:00
Redkale
d6df2055b2 2017-08-03 14:30:03 +08:00
Redkale
570aac947a 2017-08-03 12:16:14 +08:00
Redkale
1fdc33b565 2017-08-03 10:21:16 +08:00
Redkale
af8d0e978e 2017-07-27 16:52:00 +08:00
Redkale
c58022a81e Update README.md 2017-07-25 11:32:57 +08:00
Redkale
f4cf828993 Update README.md 2017-07-25 11:31:23 +08:00
Redkale
c4dc0de5fe Redkale 1.8.2 开始 2017-07-25 11:24:04 +08:00
Redkale
44507a97a6 兼容Oracle的复制表结构 2017-07-25 11:05:49 +08:00
Redkale
f4a7f1cff6 修复负载均衡无法正确切换节点的BUG 2017-07-24 18:29:40 +08:00
Redkale
a5fcb45a88 2017-07-24 17:34:07 +08:00
Redkale
bc8b68526d 2017-07-24 17:32:45 +08:00
Redkale
180f201dc0 修复多个<services>节点且其下指定service时无法获取所有service实例的BUG 2017-07-24 17:20:16 +08:00
Redkale
9ab315a405 2017-07-24 16:10:13 +08:00
Redkale
27b4742b6d 增加 TransportStrategy 功能 2017-07-21 16:07:13 +08:00
Redkale
702220d18e 2017-07-19 10:51:17 +08:00
Redkale
414489da8e 2017-07-15 22:24:10 +08:00
Redkale
77057df25d 2017-07-11 11:59:12 +08:00
Redkale
2f98cd1ab5 2017-07-11 11:29:57 +08:00
Redkale
8809fe8ec9 2017-07-11 10:09:49 +08:00
Redkale
f9702a9517 WebSocket时request.keepAlive设置为false 2017-07-11 10:07:42 +08:00
Redkale
29e46b9b68 暂时屏蔽304 2017-07-11 09:47:40 +08:00
Redkale
f838e35413 返回304的响应中增加Content-Length值 2017-07-11 09:30:27 +08:00
Redkale
f3bb77c49b 增加获取最后一次ping的时间点 2017-07-10 22:46:16 +08:00
Redkale
12fa033e15 增加判断用户是否在线和获取在线用户总数接口 2017-07-05 15:57:22 +08:00
Redkale
f4abfafea2 2017-07-05 15:42:54 +08:00
Redkale
0918af71d2 CacheSource增加getKeySize方法 2017-07-05 15:18:16 +08:00
Redkale
275befa330 private方法改成protected,方便重载 2017-07-05 10:28:55 +08:00
Redkale
ab4cd8bcb6 2017-07-02 17:30:08 +08:00
Redkale
36c109b32f 2017-07-02 17:29:22 +08:00
Redkale
73a915665d 2017-07-02 17:00:59 +08:00
Redkale
bd6d71c94a 修复@RestWebSocket对应的WebSocketServlet.resourceName没有重载的BUG 2017-07-01 16:31:00 +08:00
Redkale
842e93507c WebSocketEngine.broadcastMessage 增加 Predicate<WebSocket> 参数 2017-07-01 15:46:51 +08:00
Redkale
76df1108d7 WebSocketEngine.broadcastMessage 增加 Predicate<WebSocket> 参数 2017-07-01 15:38:47 +08:00
Redkale
941d09cde2 2017-07-01 15:29:26 +08:00
Redkale
9dd3e1da07 允许本地模式的Service通过@Resource可以获取Application、ResourceFactory等资源 2017-06-30 13:35:44 +08:00
Redkale
2bf73245ec Redkale 1.8.1 开始 2017-06-26 09:40:30 +08:00
Redkale
b0ab792f72 2017-06-24 22:45:19 +08:00
Redkale
0df9a940c5 2017-06-24 16:24:13 +08:00
Redkale
fc35fc5abc 2017-06-24 15:26:52 +08:00
Redkale
eaa0a99933 2017-06-24 12:33:48 +08:00
Redkale
83bdb97842 2017-06-24 12:31:20 +08:00
Redkale
a71a4d0fed 2017-06-24 10:47:41 +08:00
Redkale
835435c220 2017-06-24 10:38:41 +08:00
Redkale
c524ba1797 2017-06-24 10:32:00 +08:00
Redkale
f254b48693 2017-06-24 10:09:26 +08:00
Redkale
922697eb4d 2017-06-22 14:37:42 +08:00
Redkale
450e3e3ea2 2017-06-22 09:42:24 +08:00
Redkale
b31f75f4f6 2017-06-22 00:54:51 +08:00
Redkale
1d1f18b046 2017-06-21 23:05:40 +08:00
Redkale
73f942746b 2017-06-21 17:35:18 +08:00
Redkale
b6cefe8c2d 2017-06-21 17:34:08 +08:00
Redkale
ebc0e4eb41 2017-06-21 17:32:22 +08:00
Redkale
179a7b22ea 2017-06-21 16:27:18 +08:00
Redkale
0b87d9a261 2017-06-21 16:10:15 +08:00
Redkale
685a686ead 2017-06-20 21:58:20 +08:00
Redkale
568e1cf62d 2017-06-20 21:57:29 +08:00
Redkale
1d121bd2ab 2017-06-20 13:56:45 +08:00
Redkale
2ca4bdaaec 2017-06-19 13:46:32 +08:00
Redkale
878fda30f6 2017-06-19 13:45:16 +08:00
Redkale
abb611382c 2017-06-19 13:41:43 +08:00
Redkale
b53510a26f 2017-06-19 10:07:59 +08:00
Redkale
2aee84d477 2017-06-19 09:53:29 +08:00
Redkale
0ba2e25f2e 2017-06-19 08:20:52 +08:00
Redkale
98e8a7eb05 2017-06-18 22:31:13 +08:00
Redkale
62139efca9 2017-06-18 21:58:28 +08:00
Redkale
2b62cbe455 2017-06-18 21:51:20 +08:00
Redkale
e44602fe3b 2017-06-15 23:27:56 +08:00
Redkale
276cb4da92 2017-06-15 08:08:38 +08:00
Redkale
7081f94afc 2017-06-12 14:43:32 +08:00
Redkale
2d6cefeb43 2017-06-07 09:38:57 +08:00
Redkale
ea6c703ac6 2017-06-07 07:02:16 +08:00
Redkale
d1f14962fd 2017-06-07 06:59:51 +08:00
Redkale
79ca63bf81 2017-06-06 09:44:51 +08:00
Redkale
6421bc2851 2017-06-06 09:43:31 +08:00
Redkale
43f9f50f4c 2017-06-06 09:35:41 +08:00
Redkale
5f140a8ce9 2017-06-06 09:31:27 +08:00
Redkale
c0f8cdf902 2017-06-06 09:30:46 +08:00
Redkale
8d66b1b4a7 2017-06-06 08:35:57 +08:00
Redkale
8c7ee4136c 2017-06-06 08:20:47 +08:00
Redkale
d9498c9a6c 2017-06-05 16:09:06 +08:00
Redkale
08060a8c86 2017-06-05 09:18:05 +08:00
Redkale
2bdf0e4a50 2017-06-05 08:55:37 +08:00
Redkale
eb184df100 2017-06-04 11:30:07 +08:00
Redkale
cf545a731c 2017-06-04 08:03:03 +08:00
Redkale
95e18dfd48 2017-06-04 08:00:13 +08:00
Redkale
023a9abdef 2017-06-03 22:32:47 +08:00
Redkale
7f3776c224 2017-06-03 22:12:29 +08:00
Redkale
7b15ba33e0 2017-06-03 22:05:53 +08:00
Redkale
a6c105d63d 2017-06-03 18:41:08 +08:00
Redkale
10e22b0873 2017-06-03 16:50:40 +08:00
Redkale
53a35e6397 2017-06-03 10:20:36 +08:00
Redkale
b5a3c39f4f 2017-06-03 09:51:53 +08:00
Redkale
99381d4842 2017-06-02 15:24:53 +08:00
Redkale
5f2c2a9f2c 2017-06-02 14:00:14 +08:00
Redkale
dc3f318949 2017-06-02 09:46:58 +08:00
Redkale
cfae61faea 2017-06-01 20:06:46 +08:00
Redkale
dd7626b1a3 2017-06-01 15:21:28 +08:00
Redkale
2171aa1232 2017-06-01 13:23:35 +08:00
Redkale
801ad489d2 2017-06-01 11:38:49 +08:00
Redkale
c88d0b402d 2017-05-31 21:19:51 +08:00
Redkale
542bb4353b 2017-05-31 14:07:21 +08:00
Redkale
fe1e0a845a 2017-05-31 13:41:10 +08:00
Redkale
f320f4c550 2017-05-31 12:17:10 +08:00
Redkale
0ec2bf211a 2017-05-31 10:51:02 +08:00
Redkale
b3c54e4db5 2017-05-31 10:50:10 +08:00
Redkale
52838f04a9 2017-05-31 08:31:40 +08:00
Redkale
fa5bd95a2b 2017-05-30 17:12:51 +08:00
Redkale
b2e73d378c 2017-05-30 16:42:10 +08:00
Redkale
6895b31ad0 2017-05-30 16:11:29 +08:00
Redkale
56637ff7ef 2017-05-30 16:04:25 +08:00
Redkale
40b46f9c7f 2017-05-30 14:57:58 +08:00
Redkale
0aed26652d 2017-05-30 11:12:42 +08:00
Redkale
14238a0203 2017-05-30 07:22:45 +08:00
Redkale
369a70e857 2017-05-29 21:20:30 +08:00
Redkale
6ede9b0f31 2017-05-29 21:19:52 +08:00
Redkale
6c039dc8f4 2017-05-29 21:01:56 +08:00
Redkale
1e69a6755f 2017-05-29 19:02:43 +08:00
Redkale
f6c617574c 2017-05-29 17:22:12 +08:00
Redkale
2291beb5e7 2017-05-29 16:35:11 +08:00
Redkale
d8e091f888 2017-05-29 15:13:46 +08:00
Redkale
6a42ae7570 2017-05-29 15:05:39 +08:00
Redkale
756e4634d9 2017-05-29 15:03:27 +08:00
Redkale
06773ccdc0 2017-05-29 14:03:11 +08:00
Redkale
0da74be2fa 2017-05-29 09:17:54 +08:00
Redkale
1d1b732a74 2017-05-28 15:04:10 +08:00
Redkale
ab90c80785 2017-05-28 13:30:50 +08:00
Redkale
6cd232efd2 2017-05-28 10:19:56 +08:00
Redkale
96e4b8834d 2017-05-27 21:56:34 +08:00
Redkale
7ef5ddfd46 2017-05-27 21:41:24 +08:00
Redkale
73a973e0ed 2017-05-27 21:05:17 +08:00
Redkale
e0411a94f6 2017-05-27 20:44:47 +08:00
Redkale
054e853074 2017-05-27 19:34:35 +08:00
Redkale
88672b5522 2017-05-27 18:20:49 +08:00
Redkale
0a60b81a98 2017-05-27 18:08:14 +08:00
Redkale
37f8208b1b 2017-05-27 17:54:55 +08:00
Redkale
a8b9cc9753 2017-05-27 15:31:35 +08:00
Redkale
a99c7d3454 2017-05-27 15:07:24 +08:00
Redkale
b88987dd98 2017-05-27 14:59:52 +08:00
Redkale
54f4f8e35d 2017-05-27 13:18:32 +08:00
Redkale
97670261e6 2017-05-27 12:43:03 +08:00
Redkale
82a2a513f5 2017-05-27 12:31:58 +08:00
Redkale
174a8a2a0c 2017-05-27 11:54:28 +08:00
Redkale
92b3d0bbd4 2017-05-27 10:25:53 +08:00
Redkale
24c90b015a 2017-05-26 14:19:34 +08:00
Redkale
2742e935cb 2017-05-26 13:57:50 +08:00
Redkale
b7770c89b8 2017-05-26 13:52:36 +08:00
Redkale
779a9cca4d 2017-05-26 13:26:39 +08:00
Redkale
493c27beb5 2017-05-26 13:25:57 +08:00
Redkale
c68d988d51 2017-05-26 11:15:04 +08:00
Redkale
ceeb924d4d 2017-05-26 10:18:55 +08:00
Redkale
4d0a16d35d 2017-05-26 07:39:41 +08:00
Redkale
1e60adf5bb 2017-05-26 00:40:51 +08:00
Redkale
59b08684a8 2017-05-25 23:51:27 +08:00
Redkale
c326b7ed05 2017-05-25 23:06:27 +08:00
Redkale
d9bf5c8412 2017-05-25 17:54:14 +08:00
Redkale
39d4e6405f 2017-05-25 17:43:22 +08:00
Redkale
03bcea30df 2017-05-25 17:18:20 +08:00
Redkale
27b67cde0e 2017-05-25 16:50:46 +08:00
Redkale
31fca5630b 2017-05-25 16:49:01 +08:00
Redkale
3504d735c1 2017-05-25 16:01:11 +08:00
Redkale
74f554fe33 2017-05-25 15:57:18 +08:00
Redkale
b02d4e6731 2017-05-25 15:06:15 +08:00
Redkale
23fd72b116 2017-05-24 23:05:14 +08:00
Redkale
4cd1b10c35 2017-05-24 22:54:11 +08:00
Redkale
71c0763304 2017-05-24 17:57:23 +08:00
Redkale
0ea4ddb5eb 2017-05-24 17:50:49 +08:00
Redkale
9bc266ca61 2017-05-24 12:36:38 +08:00
Redkale
b202de4916 2017-05-24 10:53:51 +08:00
Redkale
7d26198e88 2017-05-24 09:29:14 +08:00
Redkale
d98e249fd7 2017-05-24 09:21:30 +08:00
Redkale
7a8b6cac9d 2017-05-23 23:23:08 +08:00
Redkale
822ac078b5 2017-05-23 23:19:16 +08:00
Redkale
5e3718af19 2017-05-23 23:16:37 +08:00
Redkale
713fdefb56 2017-05-23 23:14:30 +08:00
Redkale
804e0e27e7 2017-05-23 22:14:03 +08:00
Redkale
2653808f8f 2017-05-23 22:12:55 +08:00
Redkale
ba12df2cba 2017-05-23 20:12:32 +08:00
Redkale
d2bfa9ab56 2017-05-23 20:03:09 +08:00
Redkale
0fb108bd9b 2017-05-23 19:59:14 +08:00
Redkale
145527db38 2017-05-23 19:45:52 +08:00
Redkale
d7c50532cf 2017-05-23 18:59:56 +08:00
Redkale
6562ac0a2b 2017-05-23 14:25:24 +08:00
Redkale
6f4c9dca48 2017-05-23 13:15:13 +08:00
Redkale
f18ef4f94d 2017-05-23 12:19:42 +08:00
Redkale
4786e17243 2017-05-23 11:23:58 +08:00
Redkale
96beb9cef4 2017-05-23 11:04:54 +08:00
Redkale
a59bf92ee7 2017-05-23 09:32:52 +08:00
Redkale
cdc3dbf9ea 2017-05-22 22:21:17 +08:00
Redkale
a957a18e32 2017-05-22 22:18:03 +08:00
Redkale
95c53f99e0 2017-05-22 20:20:29 +08:00
Redkale
03ac849451 2017-05-22 20:01:52 +08:00
Redkale
d9946ceb64 2017-05-22 19:32:26 +08:00
Redkale
fda9c30dc4 2017-05-22 19:22:24 +08:00
Redkale
205162ce38 2017-05-22 17:13:16 +08:00
Redkale
f5379df63b 2017-05-22 16:47:53 +08:00
Redkale
859e56af4d 2017-05-22 16:46:59 +08:00
Redkale
a29cc94f32 2017-05-22 16:00:25 +08:00
Redkale
9e6840f5cb 2017-05-22 15:27:53 +08:00
Redkale
52d559ea4a 2017-05-22 14:41:03 +08:00
Redkale
95a2b752af 2017-05-22 13:19:12 +08:00
Redkale
33da94960c 2017-05-22 13:05:50 +08:00
Redkale
dee2002cf3 2017-05-22 12:43:09 +08:00
Redkale
d9a318bba8 2017-05-22 09:32:14 +08:00
Redkale
05925b4f78 2017-05-21 21:21:56 +08:00
Redkale
45fe7cb3e9 2017-05-21 21:00:21 +08:00
Redkale
58271c803b 2017-05-21 20:56:57 +08:00
Redkale
88942c61b5 2017-05-21 19:31:54 +08:00
Redkale
88c4824c4f 2017-05-21 19:29:56 +08:00
Redkale
62b0be802e 2017-05-21 19:26:27 +08:00
Redkale
cdec316312 2017-05-21 18:33:39 +08:00
Redkale
8dcb999444 2017-05-21 14:18:47 +08:00
Redkale
ee460b4196 2017-05-21 14:08:55 +08:00
Redkale
d049b3f9ea 2017-05-21 13:47:31 +08:00
Redkale
c244c4edab 2017-05-21 13:19:32 +08:00
Redkale
7c533ce8d3 2017-05-21 12:52:01 +08:00
Redkale
f68686114d 2017-05-21 12:29:58 +08:00
Redkale
0859dee201 2017-05-20 13:43:02 +08:00
Redkale
46ccd83acc 2017-05-20 13:40:58 +08:00
Redkale
d5e44787c0 2017-05-20 13:15:23 +08:00
Redkale
4029b09d81 2017-05-20 13:14:00 +08:00
Redkale
e939241a8c 临时 2017-05-20 13:01:43 +08:00
Redkale
cee2c47d9a 2017-05-19 13:22:51 +08:00
Redkale
ccceaa2607 2017-05-19 13:21:09 +08:00
Redkale
358a50ecc7 2017-05-19 12:53:28 +08:00
Redkale
6aabae849d 2017-05-19 12:34:00 +08:00
Redkale
60cbd9b37d 2017-05-19 11:43:46 +08:00
Redkale
df2ee8273d 2017-05-19 11:39:10 +08:00
Redkale
8bbee0aff8 2017-05-19 11:26:21 +08:00
Redkale
01ea7f07f5 2017-05-18 16:52:44 +08:00
Redkale
ba928b389b 2017-05-18 14:22:44 +08:00
Redkale
39ba0f86f6 2017-05-17 19:10:51 +08:00
Redkale
4d523d1ca4 2017-05-17 18:35:37 +08:00
Redkale
2f60fe795c 2017-05-17 18:24:04 +08:00
Redkale
c3560b0ef0 2017-05-17 18:11:44 +08:00
Redkale
804b4dc07d 2017-05-17 18:00:15 +08:00
Redkale
bb87774ba9 临时修改 2017-05-17 02:32:36 +08:00
Redkale
f76ab977d1 2017-05-17 02:17:03 +08:00
Redkale
8003252cf3 2017-05-16 21:11:18 +08:00
Redkale
95c0d0f5cf 2017-05-16 21:09:28 +08:00
Redkale
3dcc6ea28f 2017-05-16 20:14:35 +08:00
Redkale
85c708b075 2017-05-16 20:11:45 +08:00
Redkale
278c51e26b 2017-05-16 17:13:51 +08:00
Redkale
7c0e60d191 2017-05-14 20:41:29 +08:00
Redkale
d1d10f90b9 2017-05-14 20:04:40 +08:00
Redkale
3b601979f4 2017-05-14 19:42:08 +08:00
Redkale
69cc09e76d 2017-05-14 16:05:41 +08:00
Redkale
ef28e32e04 2017-05-14 15:52:15 +08:00
Redkale
9954eaf469 2017-05-14 13:29:45 +08:00
Redkale
5ce5f53ed8 2017-05-14 13:27:07 +08:00
Redkale
8e36a7b450 2017-05-14 13:07:02 +08:00
Redkale
f15754386b 2017-05-14 12:27:27 +08:00
Redkale
6cc90ac7fe 2017-05-14 11:49:53 +08:00
Redkale
3c7f10d657 2017-05-14 11:49:31 +08:00
Redkale
21c84865b9 2017-05-14 11:47:00 +08:00
Redkale
853e823a8d 2017-05-14 11:34:15 +08:00
Redkale
6d74355fc0 2017-05-13 22:37:54 +08:00
Redkale
987914e748 2017-05-13 22:35:16 +08:00
Redkale
6e66ee0c99 2017-05-13 21:15:53 +08:00
Redkale
4f7145319f 2017-05-13 18:54:39 +08:00
Redkale
ab2656cde6 2017-05-13 18:47:03 +08:00
Redkale
27468d9f0c 2017-05-13 18:44:32 +08:00
Redkale
bb8462af2a 2017-05-13 18:17:36 +08:00
Redkale
e1df150a37 2017-05-13 16:49:21 +08:00
Redkale
bee4f31323 2017-05-13 16:40:26 +08:00
Redkale
df3a1ef84d 2017-05-13 15:39:58 +08:00
Redkale
242b13fff0 2017-05-13 15:27:34 +08:00
Redkale
c3cc9de5b5 2017-05-13 14:33:44 +08:00
Redkale
72e16b88f7 2017-05-13 14:19:23 +08:00
Redkale
f1f0227dca 2017-05-13 14:18:46 +08:00
Redkale
63fe26f9cb 2017-05-13 14:16:51 +08:00
Redkale
02fcb7b089 2017-05-13 13:56:02 +08:00
Redkale
9db9db4f5e 2017-05-13 11:23:14 +08:00
Redkale
e5ce250304 2017-05-13 11:20:18 +08:00
Redkale
a5756c0b4d 2017-05-13 10:50:52 +08:00
Redkale
0be3d8a4fa 2017-05-13 09:38:28 +08:00
Redkale
017ab1ae84 2017-05-12 22:02:19 +08:00
Redkale
c622e2437d 2017-05-12 21:46:10 +08:00
Redkale
3a1f20d438 2017-05-12 21:38:30 +08:00
Redkale
2a9b64e53e 2017-05-12 21:34:46 +08:00
Redkale
225745a282 2017-05-12 21:30:18 +08:00
Redkale
83680c46e8 2017-05-12 19:56:09 +08:00
Redkale
7484b80fb2 2017-05-12 17:57:17 +08:00
Redkale
77674ac8d2 2017-05-12 17:51:27 +08:00
Redkale
564067602f 2017-05-12 14:58:52 +08:00
Redkale
26778c58c9 2017-05-12 14:21:47 +08:00
Redkale
77cd24fa42 2017-05-12 14:19:06 +08:00
Redkale
4feea0e784 重构HttpServlet 2017-05-12 13:42:10 +08:00
Redkale
681faa415f 2017-05-12 08:09:05 +08:00
Redkale
3b54484832 改造HttpBaseServlet 的preExecute 和 authenticate 方法 2017-05-11 14:56:48 +08:00
Redkale
fa2513d934 2017-05-11 13:58:33 +08:00
Redkale
5e2be5e926 2017-05-11 13:56:36 +08:00
Redkale
4c071b0a1d 2017-05-11 13:49:52 +08:00
Redkale
9e7949d9eb 2017-05-11 13:35:09 +08:00
Redkale
29843a9812 2017-05-11 13:34:33 +08:00
Redkale
48a08f27a7 2017-05-11 13:07:37 +08:00
Redkale
4f1a0849ec 2017-05-11 12:55:40 +08:00
Redkale
6676c3fd37 REST 增加 @RestBody 特性, 获取请求内容, 参数可以是String 或 byte[] 2017-05-10 23:35:47 +08:00
Redkale
6daa45ff05 2017-05-10 17:40:56 +08:00
Redkale
28f95a89df 2017-05-03 13:41:08 +08:00
Redkale
44d11dae34 2017-05-02 08:20:54 +08:00
Redkale
a1b39ba99b 2017-05-02 08:19:32 +08:00
Redkale
abcfb8f10c 2017-05-02 08:12:19 +08:00
Redkale
33f49c7632 2017-05-02 08:10:51 +08:00
Redkale
d800a33ded 2017-05-02 08:09:01 +08:00
Redkale
f587e13bdc 2017-05-02 08:08:25 +08:00
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
249 changed files with 17505 additions and 6407 deletions

View File

@@ -22,3 +22,7 @@
&nbsp;&nbsp;&nbsp;由于RedKale使用了JDK 8 内置的ASM包所以需要在源码工程中的编译器选项中加入 <b>-XDignore.symbol.file=true</b> &nbsp;&nbsp;&nbsp;由于RedKale使用了JDK 8 内置的ASM包所以需要在源码工程中的编译器选项中加入 <b>-XDignore.symbol.file=true</b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>详情请访问:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>详情请访问:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>基本文档:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
&nbsp;

36
assembly.xml Normal file
View File

@@ -0,0 +1,36 @@
<?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}/libs</directory>
<outputDirectory>libs</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

@@ -4,7 +4,7 @@ export LC_ALL="zh_CN.UTF-8"
APP_HOME=`dirname "$0"` APP_HOME=`dirname "$0"`
if [ ! -a "$APP_HOME"/conf/application.xml ]; then if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/.. APP_HOME="$APP_HOME"/..
fi fi

View File

@@ -4,7 +4,7 @@ export LC_ALL="zh_CN.UTF-8"
APP_HOME=`dirname "$0"` APP_HOME=`dirname "$0"`
if [ ! -a "$APP_HOME"/conf/application.xml ]; then if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/.. APP_HOME="$APP_HOME"/..
fi fi

View File

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

View File

@@ -8,7 +8,7 @@ export LC_ALL="zh_CN.UTF-8"
APP_HOME=`dirname "$0"` APP_HOME=`dirname "$0"`
if [ ! -a "$APP_HOME"/conf/application.xml ]; then if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/.. APP_HOME="$APP_HOME"/..
fi fi

View File

@@ -1,33 +1,33 @@
<?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>
<property name="system.property.convert.json.tiny" value="true"/>
</properties>
-->
</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>
<remoteaddr value="request.headers.X-RemoteAddress"/> <remoteaddr value="request.headers.X-RemoteAddress"/>
</request> </request>
<response> <response>
<addheader name="X-Node" value="system.property.APP_NODE" /> <defcookie domain="" path=""/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" /> <addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Credentials" value="true"/> <setheader name="Access-Control-Allow-Credentials" value="true"/>
</response> </response>
-->
<services autoload="true"/> <services autoload="true"/>
<servlets path="/pipes" autoload="true" >
<!-- <filters autoload="true"/>
<resource-servlet>
<caches limit="0"/> <rest path="/pipes" /> <!-- base指定的自定义HttpServlet子类必须标记@HttpUserType, 不设置base则视为没有当前用户信息设置 -->
<rewrite type="location" match="^/([^-]+)(-[^-\.]+)+\.html(.*)" forward="/$1.html"/>
</resource-servlet> <servlets path="/pipes" autoload="true" />
-->
</servlets>
</server> </server>
</application> </application>

View File

@@ -3,7 +3,7 @@
handlers = java.util.logging.ConsoleHandler handlers = java.util.logging.ConsoleHandler
############################################################ ############################################################
.level = FINE .level = FINER
java.level = INFO java.level = INFO
javax.level = INFO javax.level = INFO
@@ -12,12 +12,13 @@ sun.level = INFO
jdk.level = INFO jdk.level = INFO
java.util.logging.FileHandler.level = FINE java.util.logging.FileHandler.level = FINER
#10M #10M
java.util.logging.FileHandler.limit = 10485760 java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 10000 java.util.logging.FileHandler.count = 10000
java.util.logging.FileHandler.encoding = UTF-8 java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
java.util.logging.FileHandler.append = true java.util.logging.FileHandler.append = true
java.util.logging.ConsoleHandler.level = FINE java.util.logging.ConsoleHandler.level = FINER

View File

@@ -16,9 +16,9 @@
<persistence-unit name="user.read" transaction-type="RESOURCE_LOCAL"> <persistence-unit name="user.read" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode> <shared-cache-mode>ALL</shared-cache-mode>
<properties> <properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/user?autoReconnect=true&amp;characterEncoding=utf8"/> <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.user" value="system"/>
<property name="javax.persistence.jdbc.password" value="1234"/> <property name="javax.persistence.jdbc.password" value="1234"/>
</properties> </properties>
</persistence-unit> </persistence-unit>

View File

@@ -1 +1 @@
<EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD> <EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>

1
libs/readme.txt Normal file
View File

@@ -0,0 +1 @@
<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>

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

@@ -30,20 +30,23 @@
所有服务所需的资源 所有服务所需的资源
--> -->
<resources> <resources>
<!-- <!--
【节点全局唯一】 【节点全局唯一】
transport节点只能有一个用于配置所有Transport的池参数没配置该节点将自动创建一个。 transport节点只能有一个用于配置所有Transport的池参数没配置该节点将自动创建一个。
threads 线程总数, 默认: <group>节点数*CPU核数*8 threads 线程总数, 默认: <group>节点数*CPU核数*8
bufferCapacity: ByteBuffer的初始化大小 默认: 8K; bufferCapacity: ByteBuffer的初始化大小 默认: 8K;
bufferPoolSize ByteBuffer池的大小默认: <group>节点数*CPU核数*8 bufferPoolSize ByteBuffer池的大小默认: <group>节点数*CPU核数*8
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
--> -->
<transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/> <transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/>
<!-- <!--
一个组包含多个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">
@@ -57,9 +60,21 @@
--> -->
<node addr="127.0.0.1" port="7070"/> <node addr="127.0.0.1" port="7070"/>
</group> </group>
<!--
全局的数据源设置, 可以是CacheSource、DataSource JDBC的DataSource通常通过persistence.xml配置此处多用于CacheSource的配置
name: 资源名,用于依赖注入。
value类名必须是CacheSource或DataSource的子类且必须实现Service接口。
groups: 指定groups。
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
-->
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
<node addr="127.0.0.1" port="7070"/>
</source>
<!-- <!--
【节点全局唯一】 【节点全局唯一】
全局的参数配置, 可以通过@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 +85,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,20 +94,21 @@
<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、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线、减号 name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
host: 服务所占address 默认: 0.0.0.0 host: 服务所占address 默认: 0.0.0.0
port: required 服务所占端口 port: required 服务所占端口
root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root
lib: server额外的class目录 默认为 lib: server额外的class目录 默认为${APP_HOME}/libs/*;
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开 excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
charset: 文本编码, 默认: UTF-8 charset: 文本编码, 默认: UTF-8
backlog: 默认10K backlog: 默认10K
threads 线程总数, 默认: CPU核数*16 threads 线程总数, 默认: CPU核数*16
maxbody: request.body最大值 默认: 64K maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 默认: 8K; 如果是HTTP协议则默认: 16K + 8B (兼容HTTP 2.0) bufferCapacity: ByteBuffer的初始化大小 默认: 8K; 如果是HTTP协议则默认: 16K + 16B (兼容HTTP 2.0、WebSocket)
bufferPoolSize ByteBuffer池的大小默认: CPU核数*512 bufferPoolSize ByteBuffer池的大小默认: CPU核数*512
responsePoolSize Response池的大小默认: CPU核数*256 responsePoolSize Response池的大小默认: CPU核数*256
readTimeoutSecond: 读操作超时秒数, 默认0 表示永久不超时 readTimeoutSecond: 读操作超时秒数, 默认0 表示永久不超时
@@ -102,8 +120,7 @@
<!-- <!--
加载所有的Service服务; 加载所有的Service服务;
在同一个进程中同一个name同一类型的Service将共用同一个实例 在同一个进程中同一个name同一类型的Service将共用同一个实例
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Service类: autoload="true" 默认值. 自动加载classpath下所有的Service类
server.lib; server.lib/*; server.classes;
autoload="false" 需要显著的指定Service类 autoload="false" 需要显著的指定Service类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
@@ -118,6 +135,7 @@
<!-- <!--
name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。 name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。
groups: 显式指定groups覆盖<services>节点的groups默认值。 groups: 显式指定groups覆盖<services>节点的groups默认值。
ignore: 是否禁用, 默认为false。
--> -->
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/> <service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
<!-- 给Service增加配置属性 --> <!-- 给Service增加配置属性 -->
@@ -128,21 +146,51 @@
</service> </service>
</services> </services>
<!--
加载所有的Filter服务;
autoload="true" 默认值.
autoload="false" 需要显著的指定Filter类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<filters autoload="true" includes="" excludes="">
<!--
显著加载指定的Filter类
value=: Filter类名。必须与Server的协议层相同HTTP必须是HttpFilter
ignore: 是否禁用, 默认为false。
-->
<!-- 显著加载指定的Filter类 -->
<filter value="com.xxx.XXX1Filter"/>
<!-- 给Filter增加配置属性 -->
<filter value="com.xxx.XXX12Filter">
<!-- property节点值在 public void init(AnyValue conf) 方法中可以通过 AnyValue properties = conf.getAnyValue("properties");获取 -->
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</filter>
</filters>
<!-- <!--
REST的核心配置项 REST的核心配置项
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个 当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置系统会自动生成)
base: REST服务的BaseServlet必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。 path: servlet的ContextPath前缀 默认为空
base: REST服务的BaseServlet必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
autoload默认值"true" 默认值. 加载当前server所能使用的Servce对象; autoload默认值"true" 默认值. 加载当前server所能使用的Servce对象;
mustsign默认值"true" 是否只加载标记为RestService的Service类默认只加载标记RestService且ignore=false的Service
includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
--> -->
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes=""> <rest path="/pipes" base="org.redkale.net.http.HttpServlet" autoload="true" includes="" excludes="">
<!-- <!--
value: Service类名列出的表示必须被加载的Service对象 value: Service类名列出的表示必须被加载的Service对象
ignore: 是否忽略设置为true则不会加载该Service对象默认值为false ignore: 是否忽略设置为true则不会加载该Service对象默认值为false
--> -->
<service value="com.xxx.XXXXService"/> <service value="com.xxx.XXXXService"/>
<!--
value: WebSocket类名列出的表示必须被加载且标记为@RestWebSocket的WebSocket对象
ignore: 是否忽略设置为true则不会加载该RestWebSocket对象默认值为false
-->
<websocket value="com.xxx.XXXXRestWebSocket"/>
</rest> </rest>
<!-- <!--
@@ -163,11 +211,14 @@
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值 如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值 如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader 例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader
options 节点: 设置了该节点却auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
--> -->
<response> <response>
<defcookie domain="" path=""/> <defcookie domain="" path=""/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" /> <addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/>
<setheader name="Access-Control-Allow-Credentials" value="true"/> <setheader name="Access-Control-Allow-Credentials" value="true"/>
<options auto="true" />
</response> </response>
<!-- <!--
@@ -198,14 +249,17 @@
<!-- <!--
加载所有的Servlet服务; 加载所有的Servlet服务;
path: servlet的ContextPath前缀 默认为空 path: servlet的ContextPath前缀 默认为空
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Servlet类: autoload="true" 默认值. 自动加载classpath下所有的Servlet类
${APP_HOME}/lib; ${APP_HOME}/root/lib/*; ${APP_HOME}/root/classes;
autoload="false" 需要显著的指定Service类 autoload="false" 需要显著的指定Service类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
--> -->
<servlets path="/pipes" autoload="true" includes="" excludes=""> <servlets path="/pipes" autoload="true" includes="" excludes="">
<!-- 显著加载指定的Servlet --> <!--
显著加载指定的Servlet类
value=: Servlet类名。必须与Server的协议层相同HTTP必须是HttpServlet
ignore: 是否禁用, 默认为false。
-->
<servlet value="com.xxx.XXX1Servlet" /> <servlet value="com.xxx.XXX1Servlet" />
<servlet value="com.xxx.XXX2Servlet" /> <servlet value="com.xxx.XXX2Servlet" />
<servlet value="com.xxx.XXX3Servlet" > <servlet value="com.xxx.XXX3Servlet" >

View File

@@ -15,7 +15,9 @@ com.sun.level = INFO
java.util.logging.FileHandler.limit = 10485760 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-%d.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-warnerr-%d.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

@@ -3,9 +3,16 @@
<persistence> <persistence>
<!-- 系统基本库 --> <!-- 系统基本库 -->
<persistence-unit name="demouser"> <persistence-unit name="demouser">
<!-- 为NONE表示不启动缓存@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
<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"/>
<!--
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存
-->
<property name="javax.persistence.cachemode" value="ALL"/>
<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 +23,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"/>
@@ -36,7 +44,6 @@
</persistence-unit> </persistence-unit>
<!-- IM消息库 --> <!-- IM消息库 -->
<persistence-unit name="demoim"> <persistence-unit name="demoim">
<shared-cache-mode>NONE</shared-cache-mode>
<properties> <properties>
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 --> <!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>

View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 值越大,优先级越高
*
* @since Common Annotations 1.2
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Priority {
int value();
}

View File

@@ -0,0 +1,32 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javax.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @since Common Annotations 1.0
*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {
public enum AuthenticationType {
CONTAINER,
APPLICATION
}
public String name() default "";
public Class<?> type() default Object.class;
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
public boolean shareable() default true;
public String description() default "";
public String mappedName() default "";
public String lookup() default "";
}

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

@@ -15,23 +15,26 @@ 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 final class ApiDocsService {
private final Application app; private final Application app; //Application全局对象
public ApiDocs(Application app) { public ApiDocsService(Application app) {
this.app = app; this.app = app;
} }
public void run() throws Exception { public void run() throws Exception {
List<Map> serverList = new ArrayList<>(); List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
__prefix.setAccessible(true);
Map<String, Map<String, Map<String, Object>>> 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;
@@ -49,20 +52,20 @@ public class ApiDocs extends HttpBaseServlet {
continue; continue;
} }
final Map<String, Object> servletmap = new LinkedHashMap<>(); final Map<String, Object> servletmap = new LinkedHashMap<>();
String prefix = _prefix(servlet); String prefix = (String) __prefix.get(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);
final Class selfClz = servlet.getClass(); final Class selfClz = servlet.getClass();
Class clz = servlet.getClass(); Class clz = servlet.getClass();
HashSet<String> actionurls = new HashSet<>(); HashSet<String> actionurls = new HashSet<>();
@@ -70,18 +73,18 @@ public class ApiDocs extends HttpBaseServlet {
if (Modifier.isAbstract(clz.getModifiers())) break; if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) { for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue; if (method.getParameterCount() != 2) continue;
WebAction action = method.getAnnotation(WebAction.class); HttpMapping action = method.getAnnotation(HttpMapping.class);
if (action == null) continue; if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法 if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final Map<String, Object> actionmap = new LinkedHashMap<>(); final Map<String, Object> mappingmap = new LinkedHashMap<>();
if (actionurls.contains(action.url())) continue; if (actionurls.contains(action.url())) continue;
actionmap.put("url", prefix + action.url()); mappingmap.put("url", prefix + action.url());
actionurls.add(action.url()); actionurls.add(action.url());
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null); mappingmap.put("auth", action.auth());
actionmap.put("actionid", action.actionid()); mappingmap.put("actionid", action.actionid());
actionmap.put("comment", action.comment()); mappingmap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>(); List<Map> paramsList = new ArrayList<>();
actionmap.put("params", paramsList); mappingmap.put("params", paramsList);
List<String> results = new ArrayList<>(); List<String> results = new ArrayList<>();
for (final Class rtype : action.results()) { for (final Class rtype : action.results()) {
results.add(rtype.getName()); results.add(rtype.getName());
@@ -110,7 +113,7 @@ public class ApiDocs extends HttpBaseServlet {
} }
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null)); fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable())); fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) { if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue; if (field.getAnnotation(RestAddress.class) != null) continue;
} }
@@ -119,8 +122,8 @@ public class ApiDocs extends HttpBaseServlet {
} while ((loop = loop.getSuperclass()) != Object.class); } while ((loop = loop.getSuperclass()) != Object.class);
typesmap.put(rtype.getName(), typemap); typesmap.put(rtype.getName(), typemap);
} }
actionmap.put("results", results); mappingmap.put("results", results);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) { for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>(); final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray(); final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type(); final Class ptype = isarray ? param.type().getComponentType() : param.type();
@@ -159,7 +162,7 @@ public class ApiDocs extends HttpBaseServlet {
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null)); fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable())); fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) { if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue; if (field.getAnnotation(RestAddress.class) != null) continue;
} }
@@ -169,17 +172,17 @@ public class ApiDocs extends HttpBaseServlet {
typesmap.put(ptype.getName(), typemap); typesmap.put(ptype.getName(), typemap);
} }
actionmap.put("result", action.result()); mappingmap.put("result", action.result());
actionsList.add(actionmap); mappingsList.add(mappingmap);
} }
} while ((clz = clz.getSuperclass()) != HttpServlet.class); } while ((clz = clz.getSuperclass()) != HttpServlet.class);
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url"))); mappingsList.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<>();
@@ -194,7 +197,7 @@ public class ApiDocs extends HttpBaseServlet {
if (doctemplate.isFile() && doctemplate.canRead()) { if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate); in = new FileInputStream(doctemplate);
} }
if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html"); if (in == null) in = ApiDocsService.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"));
@@ -202,8 +205,4 @@ public class ApiDocs extends HttpBaseServlet {
outhtml.close(); outhtml.close();
} }
@Override
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true;
}
} }

View File

@@ -5,8 +5,10 @@
*/ */
package org.redkale.boot; package org.redkale.boot;
import org.redkale.util.RedkaleClassLoader;
import org.redkale.net.TransportGroupInfo;
import java.io.*; import java.io.*;
import java.lang.reflect.Modifier; import java.lang.reflect.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.*; import java.nio.channels.*;
@@ -15,24 +17,35 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
import java.util.logging.*; import java.util.logging.*;
import javax.annotation.Resource;
import javax.xml.parsers.*; import javax.xml.parsers.*;
import org.redkale.boot.ClassFilter.FilterEntry; import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.Convert;
import org.redkale.convert.bson.BsonFactory; import org.redkale.convert.bson.BsonFactory;
import org.redkale.convert.json.JsonFactory; import org.redkale.convert.json.JsonFactory;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.net.http.MimeType; import org.redkale.net.http.MimeType;
import org.redkale.net.sncp.SncpClient; import org.redkale.net.sncp.*;
import org.redkale.service.Service; import org.redkale.service.Service;
import org.redkale.source.*; import org.redkale.source.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.watch.WatchFactory; import org.redkale.watch.*;
import org.w3c.dom.*; import org.w3c.dom.*;
import sun.misc.Signal;
/** /**
* 编译时需要加入: -XDignore.symbol.file=true *
* 进程启动类,全局对象。 <br>
* <pre>
* 程序启动执行步骤:
* 1、读取application.xml
* 2、进行classpath扫描动态加载Service、WebSocket与Servlet
* 3、优先加载所有SNCP协议的服务再加载其他协议服务 最后加载WATCH协议的服务
* 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,67 +53,97 @@ 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 /**
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR"; * 当前Service所属的SNCP Server的地址 类型: SocketAddress、InetSocketAddress、String <br>
*/
public static final String RESNAME_SNCP_ADDR = "SNCP_ADDR";
//当前SNCP Server所属的组 类型: String /**
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP"; * 当前Service所属的SNCP Server所属的组 类型: String<br>
*/
public static final String RESNAME_SNCP_GROUP = "SNCP_GROUP";
//当前Server的ROOT目录 类型String、File、Path /**
* "SERVER_ROOT" 当前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;
final Map<InetSocketAddress, String> globalNodes = new HashMap<>(); //本地IP地址
final Map<String, GroupInfo> globalGroups = new HashMap<>();
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<>();
final ObjectPool<ByteBuffer> transportBufferPool; //传输端的TransportFactory
final TransportFactory transportFactory;
final ExecutorService transportExecutor;
final AsynchronousChannelGroup transportChannelGroup;
//全局根ResourceFactory
final ResourceFactory resourceFactory = ResourceFactory.root(); final ResourceFactory resourceFactory = ResourceFactory.root();
//服务配置项
final AnyValue config;
//临时计数器
CountDownLatch servicecdl; //会出现两次赋值 CountDownLatch servicecdl; //会出现两次赋值
//是否启动了WATCH协议服务
boolean watching;
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
//是否用于main方法运行
private final boolean singletonrun; private final boolean singletonrun;
private final WatchFactory watchFactory = WatchFactory.root(); //根WatchFactory
//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;
//根ClassLoader
private final RedkaleClassLoader classLoader;
//Server根ClassLoader
private final RedkaleClassLoader serverClassLoader;
private Application(final AnyValue config) { private Application(final AnyValue config) {
this(false, config); this(false, config);
} }
@@ -164,7 +207,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,23 +233,25 @@ 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 ------------------------------"); this.classLoader = new RedkaleClassLoader(Thread.currentThread().getContextClassLoader());
logger.log(Level.INFO, "------------------------------- Redkale " + Redkale.getDotedVersion() + " -------------------------------");
//------------------配置 <transport> 节点 ------------------ //------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null; ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null; ExecutorService transportExec = null;
AsynchronousChannelGroup transportGroup = null; AsynchronousChannelGroup transportGroup = null;
final AnyValue resources = config.getAnyValue("resources"); final AnyValue resources = config.getAnyValue("resources");
TransportStrategy strategy = null;
if (resources != null) { if (resources != null) {
AnyValue transportConf = resources.getAnyValue("transport"); AnyValue transportConf = resources.getAnyValue("transport");
int groupsize = resources.getAnyValues("group").length; int groupsize = resources.getAnyValues("group").length;
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue(); if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
if (transportConf != null) { if (transportConf != null) {
//--------------transportBufferPool----------- //--------------transportBufferPool-----------
AtomicLong createBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.creatCounter"); AtomicLong createBufferCounter = new AtomicLong();
AtomicLong cycleBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.cycleCounter"); AtomicLong cycleBufferCounter = new AtomicLong();
final int bufferCapacity = transportConf.getIntValue("bufferCapacity", 8 * 1024); final int bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), 8 * 1024), 4 * 1024);
final int bufferPoolSize = transportConf.getIntValue("bufferPoolSize", groupsize * Runtime.getRuntime().availableProcessors() * 8); final int bufferPoolSize = parseLenth(transportConf.getValue("bufferPoolSize"), groupsize * Runtime.getRuntime().availableProcessors() * 8);
final int threads = transportConf.getIntValue("threads", groupsize * Runtime.getRuntime().availableProcessors() * 8); final int threads = parseLenth(transportConf.getValue("threads"), groupsize * Runtime.getRuntime().availableProcessors() * 8);
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize, transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> { (Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false; if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false;
@@ -214,6 +260,10 @@ public final class Application {
}); });
//-----------transportChannelGroup-------------- //-----------transportChannelGroup--------------
try { try {
final String strategyClass = transportConf.getValue("strategy");
if (strategyClass != null && !strategyClass.isEmpty()) {
strategy = (TransportStrategy) classLoader.loadClass(strategyClass).newInstance();
}
final AtomicInteger counter = new AtomicInteger(); final AtomicInteger counter = new AtomicInteger();
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> { transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
Thread t = new Thread(r); Thread t = new Thread(r);
@@ -228,17 +278,43 @@ public final class Application {
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";"); logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
} }
} }
this.transportBufferPool = transportPool; if (transportGroup == null) {
this.transportExecutor = transportExec; final AtomicInteger counter = new AtomicInteger();
this.transportChannelGroup = transportGroup; transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("Transport-Thread-" + counter.incrementAndGet());
return t;
});
try {
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
this.transportFactory = new TransportFactory(transportExec, transportPool, transportGroup, strategy);
Thread.currentThread().setContextClassLoader(this.classLoader);
this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
} }
public ResourceFactory getResourceFactory() { public ResourceFactory getResourceFactory() {
return resourceFactory; return resourceFactory;
} }
public WatchFactory getWatchFactory() { public TransportFactory getTransportFactory() {
return watchFactory; return transportFactory;
}
public RedkaleClassLoader getClassLoader() {
return classLoader;
}
public RedkaleClassLoader getServerClassLoader() {
return serverClassLoader;
}
public List<NodeServer> getNodeServers() {
return new ArrayList<>(servers);
} }
public File getHome() { public File getHome() {
@@ -249,8 +325,8 @@ public final class Application {
return startTime; return startTime;
} }
private void initLogging() { public AnyValue getAppConfig() {
return config;
} }
public void init() throws Exception { public void init() throws Exception {
@@ -264,12 +340,12 @@ 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");
Server.loadLib(logger, lib); Server.loadLib(classLoader, logger, lib);
initLogging();
//------------------------------------------------------------------------ //------------------------------------------------------------------------
final AnyValue resources = config.getAnyValue("resources"); final AnyValue resources = config.getAnyValue("resources");
if (resources != null) { if (resources != null) {
@@ -295,6 +371,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.")) {
@@ -307,15 +384,75 @@ 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());
this.resourceFactory.register(JsonFactory.root().getConvert()); this.resourceFactory.register(JsonFactory.root().getConvert());
this.resourceFactory.register("bsonconvert", Convert.class, BsonFactory.root().getConvert());
this.resourceFactory.register("jsonconvert", Convert.class, JsonFactory.root().getConvert());
//只有WatchService才能加载Application、WatchFactory
final Application application = this;
this.resourceFactory.register(new ResourceFactory.ResourceLoader() {
@Override
public void load(ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) {
try {
Resource res = field.getAnnotation(Resource.class);
if (res == null) return;
if (Sncp.isRemote((Service) src)) return; //远程模式不得注入
Class type = field.getType();
if (type == Application.class) {
field.set(src, application);
} else if (type == ResourceFactory.class) {
field.set(src, res.name().equalsIgnoreCase("server") ? rf : (res.name().isEmpty() ? application.resourceFactory : null));
} else if (type == TransportFactory.class) {
field.set(src, application.transportFactory);
} else if (type == NodeSncpServer.class) {
NodeServer server = null;
for (NodeServer ns : application.getNodeServers()) {
if (ns.getClass() == NodeSncpServer.class) continue;
if (res.name().equals(ns.server.getName())) {
server = ns;
break;
}
}
field.set(src, server);
} else if (type == NodeHttpServer.class) {
NodeServer server = null;
for (NodeServer ns : application.getNodeServers()) {
if (ns.getClass() == NodeHttpServer.class) continue;
if (res.name().equals(ns.server.getName())) {
server = ns;
break;
}
}
field.set(src, server);
} else if (type == NodeWatchServer.class) {
NodeServer server = null;
for (NodeServer ns : application.getNodeServers()) {
if (ns.getClass() == NodeWatchServer.class) continue;
if (res.name().equals(ns.server.getName())) {
server = ns;
break;
}
}
field.set(src, server);
}
// if (type == WatchFactory.class) {
// field.set(src, application.watchFactory);
// }
} catch (Exception e) {
logger.log(Level.SEVERE, "Resource inject error", e);
}
}
@Override
public boolean autoNone() {
return false;
}
}, Application.class, ResourceFactory.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
//--------------------------------------------------------------------------
initResources(); initResources();
} }
@@ -324,30 +461,33 @@ public final class Application {
final AnyValue resources = config.getAnyValue("resources"); final AnyValue resources = config.getAnyValue("resources");
if (resources != null) { if (resources != null) {
//------------------------------------------------------------------------ //------------------------------------------------------------------------
for (AnyValue conf : resources.getAnyValues("group")) { for (AnyValue conf : resources.getAnyValues("group")) {
final String group = conf.getValue("name", ""); final String group = conf.getValue("name", "");
final String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase(); final String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase();
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) { if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol")); throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
} }
GroupInfo ginfo = globalGroups.get(group); TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, conf.getValue("subprotocol", ""), new LinkedHashSet<>());
if (ginfo == null) {
ginfo = new GroupInfo(group, protocol, conf.getValue("kind", ""), new LinkedHashSet<>());
globalGroups.put(group, ginfo);
}
for (AnyValue node : conf.getAnyValues("node")) { for (AnyValue node : conf.getAnyValues("node")) {
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port")); final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
ginfo.addrs.add(addr); ginfo.putAddress(addr);
String oldgroup = globalNodes.get(addr);
if (oldgroup != null) throw new RuntimeException(addr + " had one more group " + (globalNodes.get(addr)));
globalNodes.put(addr, group);
} }
transportFactory.addGroupInfo(ginfo);
} }
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
} }
public void restoreConfig() throws IOException {
synchronized (this) {
File confFile = new File(this.home, "conf/application.xml");
confFile.renameTo(new File(this.home, "conf/application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
ps.append(config.toXML("application"));
ps.close();
}
}
private void startSelfServer() throws Exception { private void startSelfServer() throws Exception {
final Application application = this; final Application application = this;
new Thread() { new Thread() {
@@ -392,7 +532,7 @@ public final class Application {
} }
} else if ("APIDOC".equalsIgnoreCase(new String(bytes))) { } else if ("APIDOC".equalsIgnoreCase(new String(bytes))) {
try { try {
new ApiDocs(application).run(); new ApiDocsService(application).run();
buffer.clear(); buffer.clear();
buffer.put("APIDOC OK".getBytes()); buffer.put("APIDOC OK".getBytes());
buffer.flip(); buffer.flip();
@@ -423,13 +563,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 ApiDocsService(application).run();
logger.info("APIDOC OK");
return;
}
}
throw e;
}
} }
public void start() throws Exception { public void start() throws Exception {
@@ -437,23 +591,67 @@ public final class Application {
CountDownLatch timecd = new CountDownLatch(entrys.length); CountDownLatch timecd = new CountDownLatch(entrys.length);
final List<AnyValue> sncps = new ArrayList<>(); final List<AnyValue> sncps = new ArrayList<>();
final List<AnyValue> others = new ArrayList<>(); final List<AnyValue> others = new ArrayList<>();
final List<AnyValue> watchs = new ArrayList<>();
for (final AnyValue entry : entrys) { for (final AnyValue entry : entrys) {
if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) { if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) {
sncps.add(entry); sncps.add(entry);
} else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) {
watchs.add(entry);
} else { } else {
others.add(entry); others.add(entry);
} }
} }
//单向SNCP服务不需要对等group if (watchs.size() > 1) throw new RuntimeException("Found one more WATCH Server");
//if (!sncps.isEmpty() && globalNodes.isEmpty()) throw new RuntimeException("found SNCP Server node but not found <group> node info."); this.watching = !watchs.isEmpty();
runServers(timecd, sncps); //必须确保sncp都启动后再启动其他协议 runServers(timecd, sncps); //必须确保SNCP服务都启动后再启动其他服务
runServers(timecd, others); runServers(timecd, others);
runServers(timecd, watchs); //必须在所有服务都启动后再启动WATCH服务
timecd.await(); timecd.await();
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms"); //if (!singletonrun) signalHandle();
if (!singletonrun) clearPersistData();
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n");
if (!singletonrun) this.serversLatch.await(); if (!singletonrun) this.serversLatch.await();
} }
private void clearPersistData() {
File cachedir = new File(home, "cache");
if (!cachedir.isDirectory()) return;
for (File file : cachedir.listFiles()) {
if (file.getName().startsWith("persist-")) file.delete();
}
}
private void signalHandle() {
//http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html
String[] sigs = new String[]{"HUP", "TERM", "INT", "QUIT", "KILL", "TSTP", "USR1", "USR2", "STOP"};
List<sun.misc.Signal> list = new ArrayList<>();
for (String sig : sigs) {
try {
list.add(new sun.misc.Signal(sig));
} catch (Exception e) {
}
}
sun.misc.SignalHandler handler = new sun.misc.SignalHandler() {
private volatile boolean runed;
@Override
public void handle(Signal sig) {
if (runed) return;
runed = true;
logger.info(Application.this.getClass().getSimpleName() + " stoped\r\n");
System.exit(0);
}
};
for (Signal sig : list) {
try {
Signal.handle(sig, handler);
} catch (Exception e) {
}
}
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void runServers(CountDownLatch timecd, final List<AnyValue> serconfs) throws Exception { private void runServers(CountDownLatch timecd, final List<AnyValue> serconfs) throws Exception {
this.servicecdl = new CountDownLatch(serconfs.size()); this.servicecdl = new CountDownLatch(serconfs.size());
@@ -463,7 +661,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);
} }
@@ -477,13 +675,22 @@ public final class Application {
NodeServer server = null; NodeServer server = null;
if ("SNCP".equals(protocol)) { if ("SNCP".equals(protocol)) {
server = NodeSncpServer.createNodeServer(Application.this, serconf); server = NodeSncpServer.createNodeServer(Application.this, serconf);
} else if ("WATCH".equalsIgnoreCase(protocol)) {
DefaultAnyValue serconf2 = (DefaultAnyValue) serconf;
DefaultAnyValue rest = (DefaultAnyValue) serconf2.getAnyValue("rest");
if (rest == null) {
rest = new DefaultAnyValue();
serconf2.addValue("rest", rest);
}
rest.setValue("base", WatchServlet.class.getName());
server = new NodeWatchServer(Application.this, serconf);
} else if ("HTTP".equalsIgnoreCase(protocol)) { } else if ("HTTP".equalsIgnoreCase(protocol)) {
server = new NodeHttpServer(Application.this, serconf); server = new NodeHttpServer(Application.this, serconf);
} else { } else {
if (!inited.get()) { if (!inited.get()) {
synchronized (nodeClasses) { synchronized (nodeClasses) {
if (!inited.getAndSet(true)) { //加载自定义的协议SOCKS if (!inited.getAndSet(true)) { //加载自定义的协议SOCKS
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class); ClassFilter profilter = new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class, (Class[]) null);
ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter); ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter);
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys(); final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
for (FilterEntry<NodeServer> entry : entrys) { for (FilterEntry<NodeServer> entry : entrys) {
@@ -493,7 +700,9 @@ public final class Application {
p = p.toUpperCase(); p = p.toUpperCase();
if ("SNCP".equals(p) || "HTTP".equals(p)) continue; if ("SNCP".equals(p) || "HTTP".equals(p)) continue;
final Class<? extends NodeServer> old = nodeClasses.get(p); final Class<? extends NodeServer> old = nodeClasses.get(p);
if (old != null && old != type) throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")"); if (old != null && old != type) {
throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
}
nodeClasses.put(p, type); nodeClasses.put(p, type);
} }
} }
@@ -570,17 +779,6 @@ public final class Application {
System.exit(0); System.exit(0);
} }
Set<String> findSncpGroups(Transport sameGroupTransport, Collection<Transport> diffGroupTransports) {
Set<String> gs = new HashSet<>();
if (sameGroupTransport != null) gs.add(sameGroupTransport.getName());
if (diffGroupTransports != null) {
for (Transport t : diffGroupTransports) {
gs.add(t.getName());
}
}
return gs;
}
NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) { NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) {
for (NodeServer node : servers) { for (NodeServer node : servers) {
if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) { if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) {
@@ -590,11 +788,6 @@ public final class Application {
return null; return null;
} }
GroupInfo findGroupInfo(String group) {
if (group == null) return null;
return globalGroups.get(group);
}
private void shutdown() throws Exception { private void shutdown() throws Exception {
servers.stream().forEach((server) -> { servers.stream().forEach((server) -> {
try { try {
@@ -607,26 +800,31 @@ public final class Application {
}); });
for (DataSource source : dataSources) { for (DataSource source : dataSources) {
if (source == null) continue;
try { try {
source.getClass().getMethod("close").invoke(source); source.getClass().getMethod("close").invoke(source);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.FINER, "close DataSource erroneous", e); logger.log(Level.FINER, source.getClass() + " close DataSource erroneous", e);
} }
} }
for (CacheSource source : cacheSources) { for (CacheSource source : cacheSources) {
if (source == null) continue;
try { try {
source.getClass().getMethod("close").invoke(source); source.getClass().getMethod("close").invoke(source);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.FINER, "close CacheSource erroneous", e); logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e);
}
}
if (this.transportChannelGroup != null) {
try {
this.transportChannelGroup.shutdownNow();
} catch (Exception e) {
logger.log(Level.FINER, "close transportChannelGroup erroneous", e);
} }
} }
this.transportFactory.shutdownNow();
}
private static int parseLenth(String value, int defValue) {
if (value == null) return defValue;
value = value.toUpperCase().replace("B", "");
if (value.endsWith("G")) return Integer.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
if (value.endsWith("M")) return Integer.decode(value.replace("M", "")) * 1024 * 1024;
if (value.endsWith("K")) return Integer.decode(value.replace("K", "")) * 1024;
return Integer.decode(value);
} }
private static AnyValue load(final InputStream in0) { private static AnyValue load(final InputStream in0) {

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<>(); //符合条件的结果
@@ -40,6 +40,8 @@ public final class ClassFilter<T> {
private Class superClass; //符合的父类型。不为空时扫描结果的class必须是superClass的子类 private Class superClass; //符合的父类型。不为空时扫描结果的class必须是superClass的子类
private Class[] excludeSuperClasses; //不符合的父类型。
private Class<? extends Annotation> annotationClass;//符合的注解。不为空时扫描结果的class必须包含该注解 private Class<? extends Annotation> annotationClass;//符合的注解。不为空时扫描结果的class必须包含该注解
private Pattern[] includePatterns; //符合的classname正则表达式 private Pattern[] includePatterns; //符合的classname正则表达式
@@ -56,18 +58,22 @@ public final class ClassFilter<T> {
private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。 private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass) { private final ClassLoader classLoader;
this(annotationClass, superClass, null);
public ClassFilter(ClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses) {
this(classLoader, annotationClass, superClass, excludeSuperClasses, null);
} }
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, AnyValue conf) { public ClassFilter(ClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) {
this.annotationClass = annotationClass; this.annotationClass = annotationClass;
this.superClass = superClass; this.superClass = superClass;
this.excludeSuperClasses = excludeSuperClasses;
this.conf = conf; this.conf = conf;
this.classLoader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
} }
public static ClassFilter create(String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) { public static ClassFilter create(Class[] excludeSuperClasses, String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
ClassFilter filter = new ClassFilter(null, null); ClassFilter filter = new ClassFilter(null, null, null, excludeSuperClasses);
filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";")); filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";"));
filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";")); filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";"));
filter.setPrivilegeIncludes(includeValues); filter.setPrivilegeIncludes(includeValues);
@@ -93,7 +99,11 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt; * @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/ */
public final Set<FilterEntry<T>> getFilterEntrys() { public final Set<FilterEntry<T>> getFilterEntrys() {
return entrys; HashSet<FilterEntry<T>> set = new HashSet<>();
set.addAll(entrys);
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterEntrys()));
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterEntrys()));
return set;
} }
/** /**
@@ -102,7 +112,11 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt; * @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/ */
public final Set<FilterEntry<T>> getFilterExpectEntrys() { public final Set<FilterEntry<T>> getFilterExpectEntrys() {
return expectEntrys; HashSet<FilterEntry<T>> set = new HashSet<>();
set.addAll(expectEntrys);
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterExpectEntrys()));
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterExpectEntrys()));
return set;
} }
/** /**
@@ -112,8 +126,8 @@ public final class ClassFilter<T> {
*/ */
public final Set<FilterEntry<T>> getAllFilterEntrys() { public final Set<FilterEntry<T>> getAllFilterEntrys() {
HashSet<FilterEntry<T>> rs = new HashSet<>(); HashSet<FilterEntry<T>> rs = new HashSet<>();
rs.addAll(entrys); rs.addAll(getFilterEntrys());
rs.addAll(expectEntrys); rs.addAll(getFilterExpectEntrys());
return rs; return rs;
} }
@@ -153,7 +167,7 @@ public final class ClassFilter<T> {
} }
if (cf == null || clazzname.startsWith("sun.")) return; if (cf == null || clazzname.startsWith("sun.")) return;
try { try {
Class clazz = Class.forName(clazzname); Class clazz = classLoader.loadClass(clazzname);
if (!cf.accept(property, clazz, autoscan)) return; if (!cf.accept(property, clazz, autoscan)) return;
if (cf.conf != null) { if (cf.conf != null) {
if (property == null) { if (property == null) {
@@ -177,7 +191,7 @@ public final class ClassFilter<T> {
} catch (Throwable cfe) { } catch (Throwable cfe) {
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.") if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) { && !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) {
//logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe); logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe);
} }
} }
} }
@@ -247,7 +261,13 @@ public final class ClassFilter<T> {
public boolean accept(AnyValue property, Class clazz, boolean autoscan) { public boolean accept(AnyValue property, Class clazz, boolean autoscan) {
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false; if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false;
if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false; if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false;
return superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz)); boolean rs = superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
if (rs && this.excludeSuperClasses != null && this.excludeSuperClasses.length > 0) {
for (Class c : this.excludeSuperClasses) {
if (c != null && (clazz == c || c.isAssignableFrom(clazz))) return false;
}
}
return rs;
} }
public static Pattern[] toPattern(String[] regs) { public static Pattern[] toPattern(String[] regs) {
@@ -269,6 +289,18 @@ public final class ClassFilter<T> {
this.superClass = superClass; this.superClass = superClass;
} }
public Class getSuperClass() {
return superClass;
}
public Class[] getExcludeSuperClasses() {
return excludeSuperClasses;
}
public void setExcludeSuperClasses(Class[] excludeSuperClasses) {
this.excludeSuperClasses = excludeSuperClasses;
}
public void setAnnotationClass(Class<? extends Annotation> annotationClass) { public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass; this.annotationClass = annotationClass;
} }
@@ -293,10 +325,6 @@ public final class ClassFilter<T> {
return annotationClass; return annotationClass;
} }
public Class getSuperClass() {
return superClass;
}
public boolean isRefused() { public boolean isRefused() {
return refused; return refused;
} }
@@ -428,12 +456,12 @@ public final class ClassFilter<T> {
* @throws IOException 异常 * @throws IOException 异常
*/ */
public static void load(final File excludeFile, final String[] excludeRegs, final ClassFilter... filters) throws IOException { public static void load(final File excludeFile, final String[] excludeRegs, final ClassFilter... filters) throws IOException {
URLClassLoader loader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); RedkaleClassLoader loader = (RedkaleClassLoader) Thread.currentThread().getContextClassLoader();
List<URL> urlfiles = new ArrayList<>(2); List<URL> urlfiles = new ArrayList<>(2);
List<URL> urljares = new ArrayList<>(2); List<URL> urljares = new ArrayList<>(2);
final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null; final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null;
final Pattern[] excludePatterns = toPattern(excludeRegs); final Pattern[] excludePatterns = toPattern(excludeRegs);
for (URL url : loader.getURLs()) { for (URL url : loader.getAllURLs()) {
if (exurl != null && exurl.sameFile(url)) continue; if (exurl != null && exurl.sameFile(url)) continue;
if (excludePatterns != null) { if (excludePatterns != null) {
boolean skip = false; boolean skip = false;
@@ -465,6 +493,12 @@ public final class ClassFilter<T> {
if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) { if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) {
String classname = entryname.substring(0, entryname.length() - 6); String classname = entryname.substring(0, entryname.length() - 6);
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue; if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
//常见的jar跳过
if (classname.startsWith("com.mysql.")) break;
if (classname.startsWith("org.mariadb.")) break;
if (classname.startsWith("oracle.jdbc.")) break;
if (classname.startsWith("org.postgresql.")) break;
if (classname.startsWith("com.microsoft.sqlserver.")) break;
classes.add(classname); classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n"); if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) { for (final ClassFilter filter : filters) {

View File

@@ -1,74 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot;
import java.net.InetSocketAddress;
import java.util.*;
/**
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class GroupInfo {
protected String name;
protected String protocol;
protected String kind;
protected Set<InetSocketAddress> addrs;
public GroupInfo() {
}
public GroupInfo(String name, String protocol, String kind, Set<InetSocketAddress> addrs) {
this.name = name;
this.protocol = protocol;
this.kind = kind;
this.addrs = addrs;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public Set<InetSocketAddress> getAddrs() {
return addrs;
}
public Set<InetSocketAddress> copyAddrs() {
return addrs == null ? null : new LinkedHashSet<>(addrs);
}
public void setAddrs(Set<InetSocketAddress> addrs) {
this.addrs = addrs;
}
}

View File

@@ -22,6 +22,7 @@ import java.util.logging.Formatter;
* *
* @author zhangjx * @author zhangjx
*/ */
@SuppressWarnings("unchecked")
public class LogFileHandler extends Handler { public class LogFileHandler extends Handler {
/** /**
@@ -70,12 +71,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 +85,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 +99,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 +125,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 +142,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 +212,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 +300,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 +310,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

@@ -5,11 +5,12 @@
*/ */
package org.redkale.boot; package org.redkale.boot;
import java.lang.annotation.Annotation;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.*; import java.util.*;
import java.util.logging.Level; import java.util.logging.Level;
import javax.annotation.Resource; import javax.annotation.*;
import org.redkale.boot.ClassFilter.FilterEntry; import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.net.http.*; import org.redkale.net.http.*;
@@ -17,6 +18,7 @@ import org.redkale.net.sncp.Sncp;
import org.redkale.service.*; import org.redkale.service.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.watch.*;
/** /**
* HTTP Server节点的配置Server * HTTP Server节点的配置Server
@@ -29,7 +31,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生成RestServlet
protected final HttpServer httpServer; protected final HttpServer httpServer;
@@ -40,7 +42,11 @@ public class NodeHttpServer extends NodeServer {
} }
private static Server createServer(Application application, AnyValue serconf) { private static Server createServer(Application application, AnyValue serconf) {
return new HttpServer(application.getStartTime(), application.getWatchFactory()); return new HttpServer(application.getStartTime());
}
public HttpServer getHttpServer() {
return httpServer;
} }
@Override @Override
@@ -48,22 +54,42 @@ public class NodeHttpServer extends NodeServer {
return httpServer == null ? null : httpServer.getSocketAddress(); return httpServer == null ? null : httpServer.getSocketAddress();
} }
@Override
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
}
@Override
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, HttpFilter.class, new Class[]{WatchFilter.class}, null, "filters", "filter");
}
@Override @Override
protected ClassFilter<Servlet> createServletClassFilter() { protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, HttpServlet.class, null, "servlets", "servlet"); return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
} }
@Override @Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception { protected ClassFilter createOtherClassFilter() {
if (httpServer != null) loadHttpServlet(this.serverConf.getAnyValue("servlets"), servletFilter); return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
} }
@Override @Override
protected void loadService(ClassFilter serviceFilter) throws Exception { protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
super.loadService(serviceFilter); super.loadService(serviceFilter, otherFilter);
initWebSocketService(); initWebSocketService();
} }
@Override
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter);
}
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpServlet(servletFilter, otherFilter);
}
private void initWebSocketService() { private void initWebSocketService() {
final NodeServer self = this; final NodeServer self = this;
final ResourceFactory regFactory = application.getResourceFactory(); final ResourceFactory regFactory = application.getResourceFactory();
@@ -71,14 +97,23 @@ public class NodeHttpServer extends NodeServer {
try { try {
if (field.getAnnotation(Resource.class) == null) return; if (field.getAnnotation(Resource.class) == null) return;
if (!(src instanceof WebSocketServlet)) return; if (!(src instanceof WebSocketServlet)) return;
ResourceFactory.ResourceLoader loader = null;
ResourceFactory sncpResFactory = null;
for (NodeServer ns : application.servers) {
if (!ns.isSNCP()) continue;
sncpResFactory = ns.resourceFactory;
loader = sncpResFactory.findLoader(WebSocketNode.class, field);
if (loader != null) break;
}
if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment);
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(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService); regFactory.register(resourceName, WebSocketNode.class, nodeService);
resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
} }
resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
field.set(src, nodeService); field.set(src, nodeService);
} }
} catch (Exception e) { } catch (Exception e) {
@@ -87,15 +122,42 @@ public class NodeHttpServer extends NodeServer {
}, WebSocketNode.class); }, WebSocketNode.class);
} }
protected void loadHttpServlet(final AnyValue servletsConf, final ClassFilter<? extends Servlet> filter) throws Exception { @SuppressWarnings("unchecked")
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String prefix = servletsConf == null ? "" : servletsConf.getValue("path", "");
final String threadName = "[" + Thread.currentThread().getName() + "] "; final String threadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Servlet>> list = new ArrayList(filter.getFilterEntrys()); List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
for (FilterEntry<? extends Filter> en : list) {
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
final HttpFilter filter = clazz.newInstance();
resourceFactory.inject(filter, this);
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
this.httpServer.addHttpFilter(filter, filterConf);
if (sb != null) sb.append(threadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
@SuppressWarnings("unchecked")
protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter, ClassFilter<? extends WebSocket> webSocketFilter) throws Exception {
final AnyValue servletsConf = this.serverConf.getAnyValue("servlets");
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
String prefix0 = servletsConf == null ? "" : servletsConf.getValue("path", "");
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
final String prefix = prefix0;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys());
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType()); boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType()); boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
if (ws1 == ws2) return o1.getType().getName().compareTo(o2.getType().getName()); if (ws1 == ws2) {
Priority p1 = o1.getType().getAnnotation(Priority.class);
Priority p2 = o2.getType().getAnnotation(Priority.class);
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
return v == 0 ? o1.getType().getName().compareTo(o2.getType().getName()) : 0;
}
return ws1 ? -1 : 1; return ws1 ? -1 : 1;
}); });
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>(); final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
@@ -109,13 +171,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,91 +179,157 @@ 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) {
final List<Object> restedObjects = new ArrayList<>();
for (AnyValue restConf : serverConf.getAnyValues("rest")) { for (AnyValue restConf : serverConf.getAnyValues("rest")) {
loadRestServlet(prefix, restConf); loadRestServlet(webSocketFilter, restConf, restedObjects, sb);
} }
} }
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
} }
protected void loadRestServlet(final String prefix, final AnyValue restConf) throws Exception { @SuppressWarnings("unchecked")
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, 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;
String prefix0 = restConf.getValue("path", "");
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
final String prefix = prefix0;
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<>();
final Class baseServletClass = Class.forName(restConf.getValue("base", DefaultRestServlet.class.getName()));
final boolean autoload = restConf.getBoolValue("autoload", true); final boolean autoload = restConf.getBoolValue("autoload", true);
final boolean mustsign = restConf.getBoolValue("mustsign", true); //是否只加载标记@RestService的Service类 { //加载RestService
String userTypeStr = restConf.getValue("usertype");
final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr);
final Set<String> includeValues = new HashSet<>(); final Class baseServletType = this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName()));
final Set<String> excludeValues = new HashSet<>(); final Set<String> includeValues = new HashSet<>();
for (AnyValue item : restConf.getAnyValues("service")) { final Set<String> excludeValues = new HashSet<>();
if (item.getBoolValue("ignore", false)) { for (AnyValue item : restConf.getAnyValues("service")) {
excludeValues.add(item.getValue("value", "")); if (item.getBoolValue("ignore", false)) {
} else { excludeValues.add(item.getValue("value", ""));
includeValues.add(item.getValue("value", "")); } else {
} includeValues.add(item.getValue("value", ""));
}
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
super.interceptorServiceWrappers.forEach((wrapper) -> {
final Class stype = wrapper.getType();
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs != null && rs.ignore()) return;
if (mustsign && rs == null) return;
if (stype.getAnnotation(LocalService.class) != null && rs == null) return;
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
RestHttpServlet servlet = httpServer.addRestServlet(wrapper.getName(), stype, wrapper.getService(), baseServletClass, prefix, (AnyValue) null);
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest("Create RestServlet[resource=" + wrapper.getName() + "] = " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix + mappings[i];
} }
if (servlet.getClass().getSimpleName().charAt(0) != '_') { }
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
final boolean finest = logger.isLoggable(Level.FINEST);
super.interceptorServices.forEach((service) -> {
final Class stype = Sncp.getServiceType(service);
final String name = Sncp.getResourceName(service);
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs == null || rs.ignore()) return;
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
if (restedObjects.contains(service)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
return;
}
restedObjects.add(service); //避免重复创建Rest对象
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
}
});
}
if (webSocketFilter != null) { //加载RestWebSocket
final Set<String> includeValues = new HashSet<>();
final Set<String> excludeValues = new HashSet<>();
for (AnyValue item : restConf.getAnyValues("websocket")) {
if (item.getBoolValue("ignore", false)) {
excludeValues.add(item.getValue("value", ""));
} else {
includeValues.add(item.getValue("value", ""));
}
}
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
final boolean finest = logger.isLoggable(Level.FINEST);
List<FilterEntry<? extends WebSocket>> list = new ArrayList(webSocketFilter.getFilterEntrys());
for (FilterEntry<? extends WebSocket> en : list) {
Class<WebSocket> clazz = (Class<WebSocket>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) {
logger.log(Level.FINE, clazz.getName() + " cannot abstract on rest websocket, so ignore");
continue;
}
if (Modifier.isFinal(clazz.getModifiers())) {
logger.log(Level.FINE, clazz.getName() + " cannot final on rest websocket, so ignore");
continue;
}
final Class<? extends WebSocket> stype = en.getType();
RestWebSocket rs = stype.getAnnotation(RestWebSocket.class);
if (rs == null || rs.ignore()) return;
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
if (restedObjects.contains(stype)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore");
return;
}
restedObjects.add(stype); //避免重复创建Rest对象
HttpServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, prefix, en.getProperty());
if (servlet == null) return; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(threadName + " " + stype.getName() + " create RestWebSocketServlet " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings)); ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
} }
} }
}); }
//输出信息 //输出信息
if (ss != null && sb != null) { if (ss != null && !ss.isEmpty() && sb != null) {
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey())); Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
int max = 0; int max = 0;
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length(); if (as.getKey().length() > max) max = as.getKey().length();
} }
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

@@ -5,27 +5,29 @@
*/ */
package org.redkale.boot; package org.redkale.boot;
import org.redkale.util.RedkaleClassLoader;
import java.io.*; import java.io.*;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.net.InetSocketAddress; import java.net.*;
import java.nio.file.Path; import java.nio.file.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.function.*; import java.util.function.*;
import java.util.logging.*; import java.util.logging.*;
import java.util.stream.Collectors; import javax.annotation.*;
import javax.annotation.Resource;
import javax.persistence.Transient; import javax.persistence.Transient;
import static org.redkale.boot.Application.*; import static org.redkale.boot.Application.*;
import org.redkale.boot.ClassFilter.FilterEntry; import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.bson.*;
import org.redkale.net.Filter;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.net.http.WebSocketNode; import org.redkale.net.http.WebSocketServlet;
import org.redkale.net.sncp.*; import org.redkale.net.sncp.*;
import org.redkale.service.*; import org.redkale.service.*;
import org.redkale.source.*; import org.redkale.source.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
/** /**
* Server节点的初始化配置类 * Server节点的初始化配置类
@@ -44,15 +46,6 @@ public abstract class NodeServer {
//日志输出对象 //日志输出对象
protected final Logger logger; protected final Logger logger;
//日志是否为FINE级别
protected final boolean fine;
//日志是否为FINER级别
protected final boolean finer;
//日志是否为FINEST级别
protected final boolean finest;
//进程主类 //进程主类
protected final Application application; protected final Application application;
@@ -62,14 +55,19 @@ public abstract class NodeServer {
//当前Server对象 //当前Server对象
protected final Server server; protected final Server server;
//ClassLoader
protected RedkaleClassLoader serverClassLoader;
protected final Thread serverThread;
//当前Server的SNCP协议的组 //当前Server的SNCP协议的组
private String sncpGroup = null; protected String sncpGroup = null;
//SNCP服务的地址 非SNCP为null //SNCP服务的地址 非SNCP为null
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,49 +76,26 @@ 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;
this.resourceFactory = application.getResourceFactory().createChild(); this.resourceFactory = application.getResourceFactory().createChild();
this.server = server; this.server = server;
this.logger = Logger.getLogger(this.getClass().getSimpleName()); this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.fine = logger.isLoggable(Level.FINE); this.serverClassLoader = new RedkaleClassLoader(application.getServerClassLoader());
this.finer = logger.isLoggable(Level.FINER); Thread.currentThread().setContextClassLoader(this.serverClassLoader);
this.finest = logger.isLoggable(Level.FINEST); this.serverThread = Thread.currentThread();
}
protected Consumer<Runnable> getExecutor() throws Exception {
if (server == null) return null;
final Field field = Server.class.getDeclaredField("context");
field.setAccessible(true);
return new Consumer<Runnable>() {
private Context context;
@Override
public void accept(Runnable t) {
if (context == null && server != null) {
try {
this.context = (Context) field.get(server);
} catch (Exception e) {
logger.log(Level.SEVERE, "Server (" + server.getSocketAddress() + ") cannot find Context", e);
}
}
if (context == null) {
t.run();
} else {
context.submit(t);
}
}
};
} }
public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) { public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) {
@@ -134,15 +109,19 @@ public abstract class NodeServer {
public void init(AnyValue config) throws Exception { public void init(AnyValue config) throws Exception {
this.serverConf = config == null ? AnyValue.create() : config; this.serverConf = config == null ? AnyValue.create() : config;
if (isSNCP()) { // SNCP协议 if (isSNCP()) { // SNCP协议
String host = this.serverConf.getValue("host", "0.0.0.0").replace("0.0.0.0", ""); String host = this.serverConf.getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0").replace("0.0.0.0", "");
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port")); this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
this.sncpGroup = application.globalNodes.get(this.sncpAddress); this.sncpGroup = application.transportFactory.findGroupName(this.sncpAddress);
//单向SNCP服务不需要对等group //单向SNCP服务不需要对等group
//if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info"); //if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
} }
//单点服务不会有 sncpAddress、sncpGroup //单点服务不会有 sncpAddress、sncpGroup
if (this.sncpAddress != null) this.resourceFactory.register(RESNAME_SERVER_ADDR, this.sncpAddress); if (this.sncpAddress != null) {
if (this.sncpGroup != null) this.resourceFactory.register(RESNAME_SERVER_GROUP, this.sncpGroup); this.resourceFactory.register(RESNAME_SNCP_ADDR, this.sncpAddress);
this.resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, this.sncpAddress);
this.resourceFactory.register(RESNAME_SNCP_ADDR, String.class, this.sncpAddress.getHostString() + ":" + this.sncpAddress.getPort());
}
if (this.sncpGroup != null) this.resourceFactory.register(RESNAME_SNCP_GROUP, this.sncpGroup);
{ {
//设置root文件夹 //设置root文件夹
String webroot = this.serverConf.getValue("root", "root"); String webroot = this.serverConf.getValue("root", "root");
@@ -155,9 +134,9 @@ public abstract class NodeServer {
resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile()); resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile());
resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath()); resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath());
final String homepath = myroot.getCanonicalPath();
//加入指定的classpath //加入指定的classpath
Server.loadLib(logger, this.serverConf.getValue("lib", "").replace("${APP_HOME}", homepath) + ";" + homepath + "/lib/*;" + homepath + "/classes"); Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", "${APP_HOME}/libs/*").replace("${APP_HOME}", application.getHome().getPath().replace('\\', '/')));
this.serverThread.setContextClassLoader(this.serverClassLoader);
} }
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService //必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
server.init(this.serverConf); server.init(this.serverConf);
@@ -165,155 +144,223 @@ public abstract class NodeServer {
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。 initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
String interceptorClass = this.serverConf.getValue("interceptor", ""); String interceptorClass = this.serverConf.getValue("interceptor", "");
if (!interceptorClass.isEmpty()) { if (!interceptorClass.isEmpty()) {
Class clazz = Class.forName(interceptorClass); Class clazz = serverClassLoader.loadClass(interceptorClass);
this.interceptor = (NodeInterceptor) clazz.newInstance(); this.interceptor = (NodeInterceptor) clazz.newInstance();
} }
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter<Service> serviceFilter = createServiceClassFilter(); ClassFilter<Service> serviceFilter = createServiceClassFilter();
ClassFilter<Filter> filterFilter = createFilterClassFilter();
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter otherFilter = createOtherClassFilter();
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
if (servletFilter == null) { ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter, filterFilter, servletFilter, otherFilter);
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter);
} else {
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter, servletFilter);
}
long e = System.currentTimeMillis() - s; long e = System.currentTimeMillis() - s;
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms"); logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
loadService(serviceFilter); //必须在servlet之前 loadService(serviceFilter, otherFilter); //必须在servlet之前
loadServlet(servletFilter); loadFilter(filterFilter, otherFilter);
loadServlet(servletFilter, otherFilter);
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor); if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
} }
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception; protected abstract void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception;
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception;
private void initResource() { private void initResource() {
final NodeServer self = this; final NodeServer self = this;
//--------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory(); final ResourceFactory appResFactory = application.getResourceFactory();
final TransportFactory appTranFactory = application.getTransportFactory();
final AnyValue resources = application.config.getAnyValue("resources");
final Map<String, AnyValue> cacheResource = new HashMap<>();
final Map<String, AnyValue> dataResources = new HashMap<>();
if (resources != null) {
for (AnyValue sourceConf : resources.getAnyValues("source")) {
try {
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
if (!Service.class.isAssignableFrom(type)) {
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
} else if (CacheSource.class.isAssignableFrom(type)) {
cacheResource.put(sourceConf.getValue("name", ""), sourceConf);
} else if (DataSource.class.isAssignableFrom(type)) {
dataResources.put(sourceConf.getValue("name", ""), sourceConf);
} else {
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "load application source resource error: " + sourceConf, e);
}
}
}
//------------------------------------- 注册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 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);
SncpClient client = Sncp.getSncpClient((Service) src); SncpClient client = Sncp.getSncpClient((Service) src);
Transport sameGroupTransport = Sncp.getSameGroupTransport((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); final Set<String> groups = new HashSet<>();
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpServer.getSncpGroup(), gs, null); if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
localServiceWrappers.add(wrapper); if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
sncpServer.consumerAccept(wrapper); Service cacheListenerService = Sncp.createLocalService(serverClassLoader, resourceName, DataCacheListenerService.class, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf((Service) src));
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
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的字段赋值;
//NodeServer.this.watchFactory.inject(src);
if (source instanceof Service) ((Service) source).init(null);
} 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);
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 CacheSource
SncpClient client = Sncp.getSncpClient((Service) src); //------------------------------------- 注册CacheSource --------------------------------------------------------
Transport sameGroupTransport = Sncp.getSameGroupTransport((Service) src); resourceFactory.register(new ResourceFactory.ResourceLoader() {
Transport[] dts = Sncp.getDiffGroupTransports((Service) src); public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
List<Transport> diffGroupTransports = dts == null ? new ArrayList<>() : Arrays.asList(dts); try {
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); if (field.getAnnotation(Resource.class) == null) return;
final CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheSourceService.class, sncpAddr, sameGroupTransport, diffGroupTransports); if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
Type genericType = field.getGenericType(); final Service srcService = (Service) src;
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null; SncpClient client = Sncp.getSncpClient(srcService);
Type valType = pt == null ? null : pt.getActualTypeArguments()[1]; final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
source.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class); final Set<String> groups = new HashSet<>();
if (field.getAnnotation(Transient.class) != null) source.setNeedStore(false); //必须在setStoreType之后 if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
application.cacheSources.add(source); if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
appResFactory.register(resourceName, genericType, source);
appResFactory.register(resourceName, CacheSource.class, source);
field.set(src, source);
rf.inject(source, self); //
((Service) source).init(null);
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheSourceService AnyValue sourceConf = cacheResource.get(resourceName);
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr); if (sourceConf == null) sourceConf = dataResources.get(resourceName);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports); final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, sncpServer.getSncpGroup(), gs, null); Object source;
sncpServer.getSncpServer().addSncpServlet(wrapper); if (DataSource.class.isAssignableFrom(sourceType)) { // DataSource
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService()); source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
application.dataSources.add((DataSource) source);
appResFactory.register(resourceName, DataSource.class, source);
} else { // CacheSource
source = (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
if (sourceType == CacheMemorySource.class) {
CacheMemorySource memorySource = (CacheMemorySource) source;
memorySource.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class);
if (field.getAnnotation(Transient.class) != null) memorySource.setNeedStore(false); //必须在setStoreType之后
}
application.cacheSources.add((CacheSource) source);
appResFactory.register(resourceName, genericType, source);
appResFactory.register(resourceName, CacheSource.class, source);
}
field.set(src, source);
rf.inject(source, self); //
if (source instanceof Service) ((Service) source).init(sourceConf);
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
sncpServer.getSncpServer().addSncpServlet((Service) source);
//logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
}
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
} }
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source); }
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e); public boolean autoNone() {
return false;
} }
}, CacheSource.class); }, CacheSource.class);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void loadService(ClassFilter serviceFilter) throws Exception { protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
if (serviceFilter == null) return; if (serviceFilter == null) return;
final String threadName = "[" + Thread.currentThread().getName() + "] "; final String threadName = "[" + Thread.currentThread().getName() + "] ";
final Set<FilterEntry<Service>> entrys = serviceFilter.getAllFilterEntrys(); final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory; ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
final ResourceFactory appResourceFactory = application.getResourceFactory();
for (FilterEntry<Service> entry : entrys) { //service实现类 final TransportFactory appTransportFactory = application.getTransportFactory();
final Class<? extends Service> type = entry.getType(); for (FilterEntry<? extends Service> entry : entrys) { //service实现类
if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过 final Class<? extends Service> serviceImplClass = entry.getType();
if (!Modifier.isPublic(type.getModifiers())) continue; if (Modifier.isFinal(serviceImplClass.getModifiers())) continue; //修饰final的类跳过
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(Local.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 ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try { try {
Service service; Service service;
if (localed) { //本地模式 boolean ws = src instanceof WebSocketServlet;
service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type, if (ws || localed) { //本地模式
NodeServer.this.sncpAddress, loadTransport(NodeServer.this.sncpGroup), loadTransports(groups)); service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, appResourceFactory, appTransportFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
} else { } else {
service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, NodeServer.this.sncpAddress, loadTransport(groups)); service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appTransportFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
} }
if (SncpClient.parseMethod(type).isEmpty()) return; //class没有可用的方法 通常为BaseService if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) return; //class没有可用的方法且没有标记启动优先级的 通常为BaseService
final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty());
for (final Class restype : wrapper.getTypes()) { final Class restype = Sncp.getResourceType(service);
if (resourceFactory.find(wrapper.getName(), restype) == null) { if (rf.find(resourceName, restype) == null) {
regFactory.register(wrapper.getName(), restype, wrapper.getService()); regFactory.register(resourceName, restype, service);
if (needinject) rf.inject(wrapper.getService()); //动态加载的Service也存在按需加载的注入资源 } else if (isSNCP() && !entry.isAutoload()) {
} else if (isSNCP() && !entry.isAutoload()) { throw new RuntimeException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + resourceName + ", group:" + groups + ") is repeat.");
throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.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); if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, service)); localServices.add(service);
if (consumer != null) consumer.accept(wrapper); interceptorServices.add(service);
if (consumer != null) consumer.accept(service);
} }
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw ex; throw ex;
@@ -322,14 +369,10 @@ public abstract class NodeServer {
} }
}; };
if (entry.isExpect()) { if (entry.isExpect()) {
ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> { ResourceType rty = entry.getType().getAnnotation(ResourceType.class);
runner.accept(rf, true); resourceFactory.register(resourceLoader, rty == null ? entry.getType() : rty.value());
};
for (final Class restype : ServiceWrapper.parseTypes(entry.getType())) {
resourceFactory.register(resourceLoader, restype);
}
} else { } else {
runner.accept(resourceFactory, false); resourceLoader.load(resourceFactory, null, entry.getName(), null, false);
} }
} }
@@ -339,30 +382,43 @@ 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(); Priority p1 = o1.getClass().getAnnotation(Priority.class);
localServiceWrappers.addAll(swlist); Priority p2 = o2.getClass().getAnnotation(Priority.class);
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
if (v != 0) return v;
int rs = Sncp.getResourceType(o1).getName().compareTo(Sncp.getResourceType(o2).getName());
if (rs == 0) rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2));
return rs;
});
localServices.clear();
localServices.addAll(swlist);
//this.loadPersistData();
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.stream().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();
} }
@@ -370,7 +426,6 @@ public abstract class NodeServer {
clds.await(); clds.await();
if (slist != null && sb != null) { if (slist != null && sb != null) {
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行) List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
Collections.sort(wlist);
for (String s : wlist) { for (String s : wlist) {
sb.append(s); sb.append(s);
} }
@@ -378,76 +433,158 @@ 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());
} }
protected List<Transport> loadTransports(final HashSet<String> groups) { private void calcMaxLength(Service y) { //计算toString中的长度
if (groups == null) return null; maxNameLength = Math.max(maxNameLength, Sncp.getResourceName(y).length());
final List<Transport> transports = new ArrayList<>(); maxClassNameLength = Math.max(maxClassNameLength, Sncp.getResourceType(y).getName().length() + 1);
for (String group : groups) {
if (this.sncpGroup == null || !this.sncpGroup.equals(group)) {
transports.add(loadTransport(group));
}
}
return transports;
} }
protected Transport loadTransport(final HashSet<String> groups) { //尚未完整实现, 先屏蔽, 单个Service在多个Server中存在的情况下进行缓存的方案还未考虑清楚
if (groups == null || groups.isEmpty()) return null; @SuppressWarnings("unchecked")
final String groupid = new ArrayList<>(groups).stream().sorted().collect(Collectors.joining(";")); //按字母排列顺序 private void loadPersistData() throws Exception {
Transport transport = application.resourceFactory.find(groupid, Transport.class); File home = application.getHome();
if (transport != null) return transport; if (home == null || !home.isDirectory()) return;
final List<Transport> transports = new ArrayList<>(); File cachedir = new File(home, "cache");
for (String group : groups) { if (!cachedir.isDirectory()) return;
transports.add(loadTransport(group)); int port = this.server.getSocketAddress().getPort();
} final String prefix = "persist-" + port + "-";
Set<InetSocketAddress> addrs = new HashSet(); final BsonConvert convert = BsonFactory.create().skipAllIgnore(true).getConvert();
transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses()))); synchronized (this.application) {
Transport first = transports.get(0); for (final File file : cachedir.listFiles((dir, name) -> name.startsWith(prefix))) {
GroupInfo ginfo = application.findGroupInfo(first.getName()); if (!file.getName().endsWith(".bat")) continue;
Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(), String classAndResname = file.getName().substring(prefix.length(), file.getName().length() - 4); //去掉尾部的.bat
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs); int pos = classAndResname.indexOf('-');
synchronized (application.resourceFactory) { String servtype = pos > 0 ? classAndResname.substring(0, pos) : classAndResname;
transport = application.resourceFactory.find(groupid, Transport.class); String resname = pos > 0 ? classAndResname.substring(pos + 1) : "";
if (transport == null) {
transport = newTransport;
application.resourceFactory.register(groupid, transport);
}
}
return transport;
}
protected Transport loadTransport(final String group) { FileInputStream in = new FileInputStream(file);
if (group == null) return null; ByteArrayOutputStream out = new ByteArrayOutputStream();
Transport transport; int b;
synchronized (application.resourceFactory) { while ((b = in.read()) != '\n') out.write(b);
transport = application.resourceFactory.find(group, Transport.class); final String[] fieldNames = out.toString().split(",");
if (transport != null) { int timeout = (int) ((System.currentTimeMillis() - file.lastModified()) / 1000);
if (this.sncpAddress != null && !this.sncpAddress.equals(transport.getClientAddress())) { for (final Service service : this.localServices) {
throw new RuntimeException(transport + "repeat create on newClientAddress = " + this.sncpAddress + ", oldClientAddress = " + transport.getClientAddress()); if (!servtype.equals(Sncp.getResourceType(service).getName())) continue;
if (!resname.equals(Sncp.getResourceName(service))) continue;
for (final String fieldName : fieldNames) {
Field field = null;
Class clzz = service.getClass();
do {
try {
field = clzz.getDeclaredField(fieldName);
break;
} catch (Exception e) {
}
} while ((clzz = clzz.getSuperclass()) != Object.class);
field.setAccessible(true);
Object val = convert.convertFrom(field.getGenericType(), in);
Persist persist = field.getAnnotation(Persist.class);
if (persist.timeout() == 0 || persist.timeout() >= timeout) {
if (Modifier.isFinal(field.getModifiers())) {
if (Map.class.isAssignableFrom(field.getType())) {
((Map) field.get(service)).putAll((Map) val);
} else if (Collection.class.isAssignableFrom(field.getType())) {
((Collection) field.get(service)).addAll((Collection) val);
}
} else {
field.set(service, val);
}
}
if (in.read() != '\n') logger.log(Level.SEVERE, servtype + "'s [" + resname + "] load value error");
}
} }
return transport; in.close();
} }
GroupInfo ginfo = application.findGroupInfo(group);
Set<InetSocketAddress> addrs = ginfo.copyAddrs();
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
application.resourceFactory.register(group, transport);
} }
return transport;
} }
//尚未完整实现, 先屏蔽
@SuppressWarnings("unchecked")
private void savePersistData() throws IOException {
File home = application.getHome();
if (home == null || !home.isDirectory()) return;
File cachedir = new File(home, "cache");
int port = this.server.getSocketAddress().getPort();
final String prefix = "persist-" + port + "-";
final BsonConvert convert = BsonFactory.create().skipAllIgnore(true).getConvert();
for (final Service service : this.localServices) {
Class clzz = service.getClass();
final Set<String> fieldNameSet = new HashSet<>();
final List<Field> fields = new ArrayList<>();
final StringBuilder sb = new StringBuilder();
do {
for (Field field : clzz.getDeclaredFields()) {
if (field.getAnnotation(Persist.class) == null) continue;
if (fieldNameSet.contains(field.getName())) continue;
if (Modifier.isStatic(field.getModifiers())) throw new RuntimeException(field + " cannot static on @" + Persist.class.getName() + " in " + clzz.getName());
if (Modifier.isFinal(field.getModifiers()) && !Map.class.isAssignableFrom(field.getType()) && !Collection.class.isAssignableFrom(field.getType())) {
throw new RuntimeException(field + " cannot final on @" + Persist.class.getName() + " in " + clzz.getName());
}
fieldNameSet.add(field.getName());
field.setAccessible(true);
try {
if (field.get(service) == null) continue;
} catch (Exception e) {
logger.log(Level.SEVERE, field + " get value error", e);
continue;
}
fields.add(field);
if (sb.length() > 0) sb.append(',');
sb.append(field.getName());
}
} while ((clzz = clzz.getSuperclass()) != Object.class);
if (fields.isEmpty()) continue; //没有数据需要缓存
// synchronized (this.application.localServices) {
// if (this.application.localServices.contains(service)) continue;
// this.application.localServices.add(service);
// }
if (!cachedir.isDirectory()) cachedir.mkdirs();
String resname = Sncp.getResourceName(service);
FileOutputStream out = new FileOutputStream(new File(cachedir, prefix + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname)) + ".bat"));
out.write(sb.toString().getBytes());
out.write('\n');
for (Field field : fields) {
Object val = null;
try {
val = field.get(service);
} catch (Exception e) {
logger.log(Level.SEVERE, field + " save value error", e);
}
convert.convertTo(out, field.getGenericType(), val);
out.write('\n');
}
out.close();
}
}
protected abstract ClassFilter<Filter> createFilterClassFilter();
protected abstract ClassFilter<Servlet> createServletClassFilter(); protected abstract ClassFilter<Servlet> createServletClassFilter();
protected ClassFilter createOtherClassFilter() {
return null;
}
protected ClassFilter<Service> createServiceClassFilter() { protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, Service.class, Annotation.class, "services", "service"); return createClassFilter(this.sncpGroup, null, Service.class, (!isSNCP() && application.watching) ? null : new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
} }
protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref, protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref,
Class inter, Class<? extends Annotation> ref2, String properties, String property) { Class inter, Class[] excludeSuperClasses, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(ref, inter, null); ClassFilter cf = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, null);
if (properties == null && properties == null) return cf; if (properties == null && properties == null) {
if (this.serverConf == null) return cf; cf.setRefused(true);
return cf;
}
if (this.serverConf == null) {
cf.setRefused(true);
return cf;
}
AnyValue[] proplist = this.serverConf.getAnyValues(properties); AnyValue[] proplist = this.serverConf.getAnyValues(properties);
if (proplist == null || proplist.length < 1) return cf; if (proplist == null || proplist.length < 1) {
cf.setRefused(true);
return cf;
}
cf = null; cf = null;
for (AnyValue list : proplist) { for (AnyValue list : proplist) {
DefaultAnyValue prop = null; DefaultAnyValue prop = null;
@@ -461,20 +598,20 @@ public abstract class NodeServer {
prop = new AnyValue.DefaultAnyValue(); prop = new AnyValue.DefaultAnyValue();
prop.addValue("groups", sc); prop.addValue("groups", sc);
} }
ClassFilter filter = new ClassFilter(ref, inter, prop); ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop);
for (AnyValue av : list.getAnyValues(property)) { // <service><servlet> 节点 for (AnyValue av : list.getAnyValues(property)) { // <service>、<filter>、<servlet> 节点
final AnyValue[] items = av.getAnyValues("property"); final AnyValue[] items = av.getAnyValues("property");
if (av instanceof DefaultAnyValue && items.length > 0) { //存在 <property>节点 if (av instanceof DefaultAnyValue && items.length > 0) { //存在 <property>节点
DefaultAnyValue dav = DefaultAnyValue.create(); DefaultAnyValue dav = DefaultAnyValue.create();
final AnyValue.Entry<String>[] strings = av.getStringEntrys(); final AnyValue.Entry<String>[] strings = av.getStringEntrys();
if (strings != null) { //将<service><servlet>节点的属性值传给dav if (strings != null) { //将<service>、<filter>、<servlet>节点的属性值传给dav
for (AnyValue.Entry<String> en : strings) { for (AnyValue.Entry<String> en : strings) {
dav.addValue(en.name, en.getValue()); dav.addValue(en.name, en.getValue());
} }
} }
final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys(); final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys();
if (anys != null) { if (anys != null) {
for (AnyValue.Entry<AnyValue> en : anys) { //将<service><servlet>节点的非property属性节点传给dav for (AnyValue.Entry<AnyValue> en : anys) { //将<service>、<filter>、<servlet>节点的非property属性节点传给dav
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue()); if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
} }
} }
@@ -485,7 +622,9 @@ public abstract class NodeServer {
dav.addValue("properties", ps); dav.addValue("properties", ps);
av = dav; av = dav;
} }
filter.filter(av, av.getValue("value"), false); if (!av.getBoolValue("ignore", false)) {
filter.filter(av, av.getValue("value"), false);
}
} }
if (list.getBoolValue("autoload", true)) { if (list.getBoolValue("autoload", true)) {
String includes = list.getValue("includes", ""); String includes = list.getValue("includes", "");
@@ -508,6 +647,24 @@ public abstract class NodeServer {
return false; return false;
} }
public boolean isWATCH() {
return false;
}
public ResourceFactory getResourceFactory() {
return resourceFactory;
}
public RedkaleClassLoader getServerClassLoader() {
return serverClassLoader;
}
public void setServerClassLoader(RedkaleClassLoader serverClassLoader) {
Objects.requireNonNull(this.serverClassLoader);
this.serverClassLoader = serverClassLoader;
this.serverThread.setContextClassLoader(serverClassLoader);
}
public InetSocketAddress getSncpAddress() { public InetSocketAddress getSncpAddress() {
return sncpAddress; return sncpAddress;
} }
@@ -532,12 +689,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 +705,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

@@ -5,14 +5,19 @@
*/ */
package org.redkale.boot; package org.redkale.boot;
import java.lang.reflect.Modifier;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.util.logging.*; import java.util.logging.Level;
import org.redkale.boot.ClassFilter.FilterEntry;
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.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
/** /**
* SNCP Server节点的配置Server
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -39,7 +44,7 @@ public class NodeSncpServer extends NodeServer {
} }
private static Server createServer(Application application, AnyValue serconf) { private static Server createServer(Application application, AnyValue serconf) {
return new SncpServer(application.getStartTime(), application.getWatchFactory()); return new SncpServer(application.getStartTime());
} }
@Override @Override
@@ -47,8 +52,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 +66,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());
} }
@@ -76,7 +81,35 @@ public class NodeSncpServer extends NodeServer {
} }
@Override @Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception { protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
if (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
}
@SuppressWarnings("unchecked")
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
for (FilterEntry<? extends Filter> en : list) {
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
final SncpFilter filter = clazz.newInstance();
resourceFactory.inject(filter, this);
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
this.sncpServer.addSncpFilter(filter, filterConf);
if (sb != null) sb.append(threadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter");
} }
@Override @Override

View File

@@ -0,0 +1,50 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot;
import java.lang.annotation.Annotation;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import org.redkale.watch.*;
/**
*
* @author zhangjx
*/
@NodeProtocol({"WATCH"})
public class NodeWatchServer extends NodeHttpServer {
public NodeWatchServer(Application application, AnyValue serconf) {
super(application, serconf);
}
@Override
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
}
@Override
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
}
@Override
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
}
@Override
protected ClassFilter createOtherClassFilter() {
return null;
}
@Override
public boolean isWATCH() {
return true;
}
}

View File

@@ -36,8 +36,8 @@
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>');

View File

@@ -0,0 +1,17 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import org.redkale.service.AbstractService;
import org.redkale.watch.WatchService;
/**
*
* @author zhangjx
*/
public abstract class AbstractWatchService extends AbstractService implements WatchService {
}

View File

@@ -0,0 +1,50 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import java.io.IOException;
import java.util.List;
import javax.annotation.Resource;
import org.redkale.boot.*;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.Comment;
/**
*
* @author zhangjx
*/
@RestService(name = "filter", catalog = "watch", repair = false)
public class FilterWatchService extends AbstractWatchService {
@Comment("Filter类名不存在")
public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002;
@Comment("Filter类名不合法")
public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003;
@Comment("Filter类名已存在")
public static final int RET_FILTER_EXISTS = 1601_0004;
@Comment("Filter的JAR包不存在")
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
@Resource
private Application application;
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
@RestParam(name = "server", comment = "Server节点名") final String serverName,
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
if (filterType == null) return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
if (jar == null) return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
List<NodeServer> nodes = application.getNodeServers();
for (NodeServer node : nodes) {
if (node.getServer().containsFilter(filterType)) return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
}
return RetResult.success();
}
}

View File

@@ -0,0 +1,17 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import org.redkale.net.http.RestService;
/**
*
* @author zhangjx
*/
@RestService(name = "server", catalog = "watch", repair = false)
public class ServerWatchService extends AbstractWatchService {
}

View File

@@ -0,0 +1,39 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.net.http.*;
/**
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@RestService(name = "service", catalog = "watch", repair = false)
public class ServiceWatchService extends AbstractWatchService {
@Resource
private Application application;
@Resource
private TransportFactory transportFactory;
// @RestMapping(name = "load", auth = false, comment = "动态增加Service")
// public RetResult loadService(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
// //待开发
// return RetResult.success();
// }
//
// @RestMapping(name = "stop", auth = false, comment = "动态停止Service")
// public RetResult stopService(String name, String type) {
// //待开发
// return RetResult.success();
// }
}

View File

@@ -0,0 +1,39 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.net.http.*;
/**
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@RestService(name = "servlet", catalog = "watch", repair = false)
public class ServletWatchService extends AbstractWatchService {
@Resource
private Application application;
@Resource
private TransportFactory transportFactory;
//
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
// //待开发
// return RetResult.success();
// }
//
// @RestMapping(name = "stop", auth = false, comment = "动态停止Servlet")
// public RetResult stopServlet(String type) {
// //待开发
// return RetResult.success();
// }
}

View File

@@ -0,0 +1,26 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.net.http.RestService;
/**
*
* @author zhangjx
*/
@RestService(name = "source", catalog = "watch", repair = false)
public class SourceWatchService extends AbstractWatchService {
@Resource
private Application application;
@Resource
private TransportFactory transportFactory;
}

View File

@@ -0,0 +1,138 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import java.io.IOException;
import java.net.*;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
/**
*
* @author zhangjx
*/
@RestService(name = "transport", catalog = "watch", repair = false)
public class TransportWatchService extends AbstractWatchService {
@Comment("不存在的Group节点")
public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001;
@Comment("非法的Node节点IP地址")
public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002;
@Comment("Node节点IP地址已存在")
public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003;
@Resource
private Application application;
@Resource
private TransportFactory transportFactory;
@RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点")
public List<TransportGroupInfo> listNodes() {
return transportFactory.getGroupInfos();
}
@RestMapping(name = "addnode", auth = false, comment = "动态增加指定Group的Node节点")
public RetResult addNode(@RestParam(name = "group", comment = "Group节点名") final String group,
@RestParam(name = "addr", comment = "节点IP") final String addr,
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
InetSocketAddress address;
try {
address = new InetSocketAddress(addr, port);
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(address).get(2, TimeUnit.SECONDS); //连接超时2秒
channel.close();
} catch (Exception e) {
return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect");
}
if (transportFactory.findGroupName(address) != null) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists");
synchronized (this) {
if (transportFactory.findGroupInfo(group) == null) {
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
}
transportFactory.addGroupInfo(group, address);
for (Service service : transportFactory.getServices()) {
if (!Sncp.isSncpDyn(service)) continue;
SncpClient client = Sncp.getSncpClient(service);
if (Sncp.isRemote(service)) {
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
client.getRemoteGroupTransport().addRemoteAddresses(address);
}
} else {
if (group.equals(client.getSameGroup())) {
client.getSameGroupTransport().addRemoteAddresses(address);
}
if (client.getDiffGroups() != null && client.getDiffGroups().contains(group)) {
for (Transport transport : client.getDiffGroupTransports()) {
transport.addRemoteAddresses(address);
}
}
}
}
DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port);
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
if (group.equals(groupconf.getValue("name"))) {
((DefaultAnyValue) groupconf).addValue("node", node);
break;
}
}
application.restoreConfig();
}
return RetResult.success();
}
@RestMapping(name = "removenode", auth = false, comment = "动态删除指定Group的Node节点")
public RetResult removeNode(@RestParam(name = "group", comment = "Group节点名") final String group,
@RestParam(name = "addr", comment = "节点IP") final String addr,
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
if (group == null) return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
final InetSocketAddress address = new InetSocketAddress(addr, port);
if (!group.equals(transportFactory.findGroupName(address))) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")");
synchronized (this) {
if (transportFactory.findGroupInfo(group) == null) {
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
}
transportFactory.removeGroupInfo(group, address);
for (Service service : transportFactory.getServices()) {
if (!Sncp.isSncpDyn(service)) continue;
SncpClient client = Sncp.getSncpClient(service);
if (Sncp.isRemote(service)) {
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
client.getRemoteGroupTransport().removeRemoteAddresses(address);
}
} else {
if (group.equals(client.getSameGroup())) {
client.getSameGroupTransport().removeRemoteAddresses(address);
}
if (client.getDiffGroups() != null && client.getDiffGroups().contains(group)) {
for (Transport transport : client.getDiffGroupTransports()) {
transport.removeRemoteAddresses(address);
}
}
}
}
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
if (group.equals(groupconf.getValue("name"))) {
((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port));
break;
}
}
application.restoreConfig();
}
return RetResult.success();
}
}

View File

@@ -6,6 +6,7 @@
package org.redkale.convert; package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;
/** /**
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入WriterJSON则不写入。 * 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入WriterJSON则不写入。
@@ -35,6 +36,28 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
} }
} }
@SuppressWarnings("unchecked")
public void convertMapTo(final Writer out, final Object... values) {
if (values == null) {
out.writeNull();
} else {
int count = values.length - values.length % 2;
out.writeMapB(count / 2);
for (int i = 0; i < count; i += 2) {
if (i > 0) out.writeArrayMark();
this.convertTo(out, (T) values[i]);
out.writeMapMark();
Object val = values[i + 1];
if (val instanceof CompletableFuture) {
this.convertTo(out, (T) ((CompletableFuture) val).join());
} else {
this.convertTo(out, (T) val);
}
}
out.writeMapE();
}
}
@Override @Override
public Type getType() { public Type getType() {
return Object.class; return Object.class;

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

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

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;
import java.lang.reflect.Type;
/**
* 二进制序列化/反序列化操作类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
public abstract class BinaryConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
protected BinaryConvert(ConvertFactory<R, W> factory) {
super(factory);
}
@Override
public final boolean isBinary() {
return true;
}
public abstract byte[] convertTo(final Object value);
public abstract byte[] convertTo(final Type type, final Object value);
public abstract byte[] convertMapTo(final Object... values);
}

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
@@ -45,6 +44,11 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
this.creator = factory.loadCreator((Class) pt.getRawType()); this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this); factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType); this.decoder = factory.loadDecoder(this.componentType);
} else if(factory.isReversible()){
this.componentType = Object.class;
this.creator = factory.loadCreator(Object.class);
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else { } else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")"); throw new ConvertException("collectiondecoder not support the type (" + type + ")");
} }

View File

@@ -9,9 +9,8 @@ import java.lang.reflect.*;
import java.util.Collection; import java.util.Collection;
/** /**
* 对象集合的序列化. * Collection的序列化操作类 <br>
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。 * 支持一定程度的泛型。 <br>
* 支持一定程度的泛型。
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -5,8 +5,12 @@
*/ */
package org.redkale.convert; package org.redkale.convert;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.util.function.Supplier;
/** /**
* 序列化操作类 * 序列化/反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -26,4 +30,17 @@ public abstract class Convert<R extends Reader, W extends Writer> {
public ConvertFactory<R, W> getFactory() { public ConvertFactory<R, W> getFactory() {
return this.factory; return this.factory;
} }
public abstract boolean isBinary();
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value);
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value);
public abstract ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values);
} }

View File

@@ -21,7 +21,7 @@ import static java.lang.annotation.RetentionPolicy.*;
@Documented @Documented
@Target({METHOD, FIELD}) @Target({METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
@Repeatable(ConvertColumns.class) @Repeatable(ConvertColumn.ConvertColumns.class)
public @interface ConvertColumn { public @interface ConvertColumn {
/** /**
@@ -31,6 +31,13 @@ public @interface ConvertColumn {
*/ */
String name() default ""; String name() default "";
/**
* 给字段取个序号ID值小靠前
*
* @return 字段排序ID
*/
int index() default 0;
/** /**
* 解析/序列化时是否屏蔽该字段 * 解析/序列化时是否屏蔽该字段
* *
@@ -44,4 +51,21 @@ public @interface ConvertColumn {
* @return JSON or BSON or ALL * @return JSON or BSON or ALL
*/ */
ConvertType type() default ConvertType.ALL; ConvertType type() default ConvertType.ALL;
/**
* ConvertColumn 的多用类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public static @interface ConvertColumns {
ConvertColumn[] value();
}
} }

View File

@@ -8,11 +8,15 @@ package org.redkale.convert;
/** /**
* ConvertColumn 对应的实体类 * ConvertColumn 对应的实体类
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
*/ */
public final class ConvertColumnEntry { public final class ConvertColumnEntry {
private int index;
private String name = ""; private String name = "";
private boolean ignore; private boolean ignore;
@@ -25,6 +29,7 @@ public final class ConvertColumnEntry {
public ConvertColumnEntry(ConvertColumn column) { public ConvertColumnEntry(ConvertColumn column) {
if (column == null) return; if (column == null) return;
this.name = column.name(); this.name = column.name();
this.index = column.index();
this.ignore = column.ignore(); this.ignore = column.ignore();
this.convertType = column.type(); this.convertType = column.type();
} }
@@ -45,6 +50,13 @@ public final class ConvertColumnEntry {
this.convertType = convertType; this.convertType = convertType;
} }
public ConvertColumnEntry(String name, int index, boolean ignore, ConvertType convertType) {
this.name = name;
this.index = index;
this.ignore = ignore;
this.convertType = convertType;
}
public String name() { public String name() {
return name == null ? "" : name; return name == null ? "" : name;
} }
@@ -69,4 +81,12 @@ public final class ConvertColumnEntry {
this.convertType = convertType; this.convertType = convertType;
} }
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
} }

View File

@@ -1,25 +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.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* ConvertColumn 的多用类
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface ConvertColumns {
ConvertColumn[] value();
}

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

@@ -5,18 +5,22 @@
*/ */
package org.redkale.convert; package org.redkale.convert;
import java.io.File;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.math.BigInteger; import java.math.*;
import java.net.*; import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler; import java.nio.channels.CompletionHandler;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.redkale.convert.ext.InetAddressSimpledCoder.InetSocketAddressSimpledCoder; import org.redkale.convert.ext.InetAddressSimpledCoder.InetSocketAddressSimpledCoder;
import org.redkale.convert.ext.*; import org.redkale.convert.ext.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 序列化模块的工厂类用于注册自定义的序列化类型获取Convert
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -85,15 +89,19 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(CharSequence.class, CharSequenceSimpledCoder.instance); this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
this.register(java.util.Date.class, DateSimpledCoder.instance); this.register(java.util.Date.class, DateSimpledCoder.instance);
this.register(BigInteger.class, BigIntegerSimpledCoder.instance); this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
this.register(BigDecimal.class, BigDecimalSimpledCoder.instance);
this.register(InetAddress.class, InetAddressSimpledCoder.instance); this.register(InetAddress.class, InetAddressSimpledCoder.instance);
this.register(DLong.class, DLongSimpledCoder.instance); this.register(DLong.class, DLongSimpledCoder.instance);
this.register(Class.class, TypeSimpledCoder.instance); this.register(Class.class, TypeSimpledCoder.instance);
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(File.class, FileSimpledCoder.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);
//--------------------------------------------------------- //---------------------------------------------------------
this.register(ByteBuffer.class, ByteBufferSimpledCoder.instance);
this.register(boolean[].class, BoolArraySimpledCoder.instance); this.register(boolean[].class, BoolArraySimpledCoder.instance);
this.register(byte[].class, ByteArraySimpledCoder.instance); this.register(byte[].class, ByteArraySimpledCoder.instance);
this.register(short[].class, ShortArraySimpledCoder.instance); this.register(short[].class, ShortArraySimpledCoder.instance);
@@ -104,6 +112,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"})
@@ -121,7 +130,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public abstract ConvertType getConvertType(); public abstract ConvertType getConvertType();
public abstract boolean isReversible(); public abstract boolean isReversible(); //是否可逆的
public abstract ConvertFactory createChild(); public abstract ConvertFactory createChild();
@@ -181,15 +190,71 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} }
final String getEntityAlias(Class clazz) { final String getEntityAlias(Class clazz) {
if (clazz == String.class) return "A";
if (clazz == int.class) return "I";
if (clazz == Integer.class) return "i";
if (clazz == long.class) return "J";
if (clazz == Long.class) return "j";
if (clazz == byte.class) return "B";
if (clazz == Byte.class) return "b";
if (clazz == boolean.class) return "Z";
if (clazz == Boolean.class) return "z";
if (clazz == short.class) return "S";
if (clazz == Short.class) return "s";
if (clazz == char.class) return "C";
if (clazz == Character.class) return "c";
if (clazz == float.class) return "F";
if (clazz == Float.class) return "f";
if (clazz == double.class) return "D";
if (clazz == Double.class) return "d";
if (clazz == String[].class) return "[A";
if (clazz == int[].class) return "[I";
if (clazz == long[].class) return "[J";
if (clazz == byte[].class) return "[B";
if (clazz == boolean[].class) return "[Z";
if (clazz == short[].class) return "[S";
if (clazz == char[].class) return "[C";
if (clazz == float[].class) return "[F";
if (clazz == double[].class) return "[D";
ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class); ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class);
if (ce != null && findEntityAlias(ce.value()) == null) entitys.put(ce.value(), clazz); if (ce != null && findEntityAlias(ce.value()) == null) entitys.put(ce.value(), clazz);
return ce == null ? clazz.getName() : ce.value(); return ce == null ? clazz.getName() : ce.value();
} }
final Class getEntityAlias(String name) { final Class getEntityAlias(String name) {
if ("A".equals(name)) return String.class;
if ("I".equals(name)) return int.class;
if ("i".equals(name)) return Integer.class;
if ("J".equals(name)) return long.class;
if ("j".equals(name)) return Long.class;
if ("B".equals(name)) return byte.class;
if ("b".equals(name)) return Byte.class;
if ("Z".equals(name)) return boolean.class;
if ("z".equals(name)) return Boolean.class;
if ("S".equals(name)) return short.class;
if ("s".equals(name)) return Short.class;
if ("C".equals(name)) return char.class;
if ("c".equals(name)) return Character.class;
if ("F".equals(name)) return float.class;
if ("f".equals(name)) return Float.class;
if ("D".equals(name)) return double.class;
if ("d".equals(name)) return Double.class;
if ("[A".equals(name)) return String[].class;
if ("[I".equals(name)) return int[].class;
if ("[J".equals(name)) return long[].class;
if ("[B".equals(name)) return byte[].class;
if ("[Z".equals(name)) return boolean[].class;
if ("[S".equals(name)) return short[].class;
if ("[C".equals(name)) return char[].class;
if ("[F".equals(name)) return float[].class;
if ("[D".equals(name)) return double[].class;
Class clazz = findEntityAlias(name); Class clazz = findEntityAlias(name);
try { try {
return clazz == null ? Class.forName(name) : clazz; return clazz == null ? Thread.currentThread().getContextClassLoader().loadClass(name) : clazz;
} catch (Exception ex) { } catch (Exception ex) {
throw new ConvertException("convert entity is " + name, ex); throw new ConvertException("convert entity is " + name, ex);
} }
@@ -390,6 +455,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
decoder = new ArrayDecoder(this, type); decoder = new ArrayDecoder(this, type);
} else if (Collection.class.isAssignableFrom(clazz)) { } else if (Collection.class.isAssignableFrom(clazz)) {
decoder = new CollectionDecoder(this, type); decoder = new CollectionDecoder(this, type);
} else if (Stream.class.isAssignableFrom(clazz)) {
decoder = new StreamDecoder(this, type);
} else if (Map.class.isAssignableFrom(clazz)) { } else if (Map.class.isAssignableFrom(clazz)) {
decoder = new MapDecoder(this, type); decoder = new MapDecoder(this, type);
} else if (clazz == Object.class) { } else if (clazz == Object.class) {
@@ -473,6 +540,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
encoder = new ArrayEncoder(this, type); encoder = new ArrayEncoder(this, type);
} else if (Collection.class.isAssignableFrom(clazz)) { } else if (Collection.class.isAssignableFrom(clazz)) {
encoder = new CollectionEncoder(this, type); encoder = new CollectionEncoder(this, type);
} else if (Stream.class.isAssignableFrom(clazz)) {
encoder = new StreamEncoder(this, type);
} else if (Map.class.isAssignableFrom(clazz)) { } else if (Map.class.isAssignableFrom(clazz)) {
encoder = new MapEncoder(this, type); encoder = new MapEncoder(this, type);
} else if (clazz == Object.class) { } else if (clazz == Object.class) {

View File

@@ -0,0 +1,25 @@
/*
* 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;
/**
* Mask接口
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public interface ConvertMask {
default byte mask(byte value) {
return value;
}
default byte unmask(byte value) {
return 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
@@ -21,6 +22,8 @@ import org.redkale.util.Attribute;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class DeMember<R extends Reader, T, F> implements Comparable<DeMember<R, T, F>> { public final class DeMember<R extends Reader, T, F> implements Comparable<DeMember<R, T, F>> {
protected int index;
protected final Attribute<T, F> attribute; protected final Attribute<T, F> attribute;
protected Decodeable<R, F> decoder; protected Decodeable<R, F> decoder;
@@ -67,9 +70,14 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
return this.attribute; return this.attribute;
} }
public int getIndex() {
return this.index;
}
@Override @Override
public final int compareTo(DeMember<R, T, F> o) { public final int compareTo(DeMember<R, T, F> o) {
if (o == null) return 1; if (o == null) return -1;
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
return this.attribute.field().compareTo(o.attribute.field()); return this.attribute.field().compareTo(o.attribute.field());
} }

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
@@ -30,6 +31,8 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
//final boolean isnumber; //final boolean isnumber;
final boolean isbool; final boolean isbool;
protected int index;
public EnMember(Attribute<T, F> attribute, Encodeable<W, F> encoder) { public EnMember(Attribute<T, F> attribute, Encodeable<W, F> encoder) {
this.attribute = attribute; this.attribute = attribute;
this.encoder = encoder; this.encoder = encoder;
@@ -60,9 +63,14 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
return attribute.field().equals(name); return attribute.field().equals(name);
} }
public int getIndex() {
return this.index;
}
@Override @Override
public final int compareTo(EnMember<W, T, F> o) { public final int compareTo(EnMember<W, T, F> o) {
if (o == null) return 1; if (o == null) return -1;
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
return this.attribute.field().compareTo(o.attribute.field()); return this.attribute.field().compareTo(o.attribute.field());
} }

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,6 +11,7 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* Map的反序列化操作类 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

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

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,8 +77,10 @@ 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))); DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t));
if (ref != null) member.index = ref.getIndex();
list.add(member);
} }
final boolean reversible = factory.isReversible(); final boolean reversible = factory.isReversible();
for (final Method method : clazz.getMethods()) { for (final Method method : clazz.getMethods()) {
@@ -85,6 +89,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,8 +102,10 @@ 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))); DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t));
if (ref != null) member.index = ref.getIndex();
list.add(member);
} }
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法 if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
for (final String constructorField : cps) { for (final String constructorField : cps) {
@@ -113,7 +120,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 +132,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,8 +68,10 @@ 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))); EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t));
if (ref != null) member.index = ref.getIndex();
list.add(member);
} }
for (final Method method : clazz.getMethods()) { for (final Method method : clazz.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue; if (Modifier.isStatic(method.getModifiers())) continue;
@@ -77,6 +80,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,8 +93,10 @@ 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))); EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t));
if (ref != null) member.index = ref.getIndex();
list.add(member);
} }
this.members = list.toArray(new EnMember[list.size()]); this.members = list.toArray(new EnMember[list.size()]);
Arrays.sort(this.members); Arrays.sort(this.members);
@@ -144,42 +150,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 +198,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

@@ -0,0 +1,94 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Stream;
/**
* Stream的反序列化操作类 <br>
* 支持一定程度的泛型。 <br>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 反解析的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
private final Type type;
private final Type componentType;
protected Creator<Stream<T>> creator;
protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
private final Object lock = new Object();
public StreamDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.componentType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("StreamDecoder not support the type (" + type + ")");
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@Override
public Stream<T> convertFrom(Reader in) {
final int len = in.readArrayB();
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 List<T> result = new ArrayList();
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
}
} else {
for (int i = 0; i < len; i++) {
result.add(localdecoder.convertFrom(in));
}
}
in.readArrayE();
return result.stream();
}
@Override
public Type getType() {
return type;
}
}

View File

@@ -0,0 +1,90 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.*;
import java.util.stream.Stream;
/**
* Stream的序列化操作类 <br>
* 支持一定程度的泛型。 <br>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 序列化的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
private final Type type;
private final Encodeable<Writer, Object> encoder;
private boolean inited = false;
private final Object lock = new Object();
public StreamEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {
if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
} else {
this.encoder = factory.loadEncoder(t);
}
} else {
this.encoder = factory.getAnyEncoder();
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@Override
public void convertTo(Writer out, Stream<T> value) {
if (value == null) {
out.writeNull();
return;
}
Object[] array = value.toArray();
if (array.length == 0) {
out.writeArrayB(0);
out.writeArrayE();
return;
}
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeArrayB(array.length);
boolean first = true;
for (Object v : array) {
if (!first) out.writeArrayMark();
encoder.convertTo(out, v);
if (first) first = false;
}
out.writeArrayE();
}
@Override
public Type getType() {
return type;
}
}

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;
import java.lang.reflect.Type;
/**
* 文本序列化/反序列化操作类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
public abstract class TextConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
protected TextConvert(ConvertFactory<R, W> factory) {
super(factory);
}
@Override
public final boolean isBinary() {
return false;
}
public abstract String convertTo(final Object value);
public abstract String convertTo(final Type type, final Object value);
public abstract String convertMapTo(final Object... values);
}

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
* *
@@ -24,7 +25,10 @@ public class BsonByteBufferReader extends BsonReader {
private ByteBuffer currentBuffer; private ByteBuffer currentBuffer;
protected BsonByteBufferReader(ByteBuffer... buffers) { protected ConvertMask mask;
protected BsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) {
this.mask = mask;
this.buffers = buffers; this.buffers = buffers;
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
} }
@@ -35,12 +39,13 @@ public class BsonByteBufferReader extends BsonReader {
this.currentIndex = 0; this.currentIndex = 0;
this.currentBuffer = null; this.currentBuffer = null;
this.buffers = null; this.buffers = null;
this.mask = null;
return false; return false;
} }
@Override @Override
protected byte currentByte() { protected byte currentByte() {
return currentBuffer.get(currentBuffer.position()); return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position()));
} }
/** /**
@@ -66,13 +71,13 @@ public class BsonByteBufferReader extends BsonReader {
public byte readByte() { public byte readByte() {
if (this.currentBuffer.hasRemaining()) { if (this.currentBuffer.hasRemaining()) {
this.position++; this.position++;
return this.currentBuffer.get(); return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
} }
for (;;) { for (;;) {
this.currentBuffer = this.buffers[++this.currentIndex]; this.currentBuffer = this.buffers[++this.currentIndex];
if (this.currentBuffer.hasRemaining()) { if (this.currentBuffer.hasRemaining()) {
this.position++; this.position++;
return this.currentBuffer.get(); return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
} }
} }
} }
@@ -83,7 +88,11 @@ public class BsonByteBufferReader extends BsonReader {
int remain = this.currentBuffer.remaining(); int remain = this.currentBuffer.remaining();
if (remain >= 2) { if (remain >= 2) {
this.position += 2; this.position += 2;
return this.currentBuffer.getChar(); if (mask == null) {
return this.currentBuffer.getChar();
} else {
return (char) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get())));
}
} }
} }
return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
@@ -95,7 +104,11 @@ public class BsonByteBufferReader extends BsonReader {
int remain = this.currentBuffer.remaining(); int remain = this.currentBuffer.remaining();
if (remain >= 2) { if (remain >= 2) {
this.position += 2; this.position += 2;
return this.currentBuffer.getShort(); if (mask == null) {
return this.currentBuffer.getShort();
} else {
return (short) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get())));
}
} }
} }
return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
@@ -107,7 +120,14 @@ public class BsonByteBufferReader extends BsonReader {
int remain = this.currentBuffer.remaining(); int remain = this.currentBuffer.remaining();
if (remain >= 4) { if (remain >= 4) {
this.position += 4; this.position += 4;
return this.currentBuffer.getInt(); if (mask == null) {
return this.currentBuffer.getInt();
} else {
return ((mask.unmask(this.currentBuffer.get()) & 0xff) << 24)
| ((mask.unmask(this.currentBuffer.get()) & 0xff) << 16)
| ((mask.unmask(this.currentBuffer.get()) & 0xff) << 8)
| (mask.unmask(this.currentBuffer.get()) & 0xff);
}
} }
} }
return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff); return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff);
@@ -119,17 +139,28 @@ public class BsonByteBufferReader extends BsonReader {
int remain = this.currentBuffer.remaining(); int remain = this.currentBuffer.remaining();
if (remain >= 8) { if (remain >= 8) {
this.position += 8; this.position += 8;
return this.currentBuffer.getLong(); if (mask == null) {
return this.currentBuffer.getLong();
} else {
return ((((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 56)
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 48)
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 40)
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 32)
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 24)
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 16)
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 8)
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff)));
}
} }
} }
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) {
@@ -149,9 +180,19 @@ public class BsonByteBufferReader extends BsonReader {
if (remain >= len) { if (remain >= len) {
this.position += len; this.position += len;
this.currentBuffer.get(bs, pos, len); this.currentBuffer.get(bs, pos, len);
if (mask != null) {
for (int i = pos, end = pos + len; i < end; i++) {
bs[i] = mask.unmask(bs[i]);
}
}
return; return;
} }
this.currentBuffer.get(bs, pos, remain); this.currentBuffer.get(bs, pos, remain);
if (mask != null) {
for (int i = pos, end = pos + remain; i < end; i++) {
bs[i] = mask.unmask(bs[i]);
}
}
this.position += remain; this.position += remain;
this.currentBuffer = this.buffers[++this.currentIndex]; this.currentBuffer = this.buffers[++this.currentIndex];
read(bs, pos + remain); read(bs, pos + remain);

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>
@@ -37,7 +37,7 @@ import org.redkale.util.*;
* *
* @author zhangjx * @author zhangjx
*/ */
public final class BsonConvert extends Convert<BsonReader, BsonWriter> { public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16)); private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
@@ -61,7 +61,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
//------------------------------ reader ----------------------------------------------------------- //------------------------------ reader -----------------------------------------------------------
public BsonReader pollBsonReader(final ByteBuffer... buffers) { public BsonReader pollBsonReader(final ByteBuffer... buffers) {
return new BsonByteBufferReader(buffers); return new BsonByteBufferReader((ConvertMask) null, buffers);
} }
public BsonReader pollBsonReader(final InputStream in) { public BsonReader pollBsonReader(final InputStream in) {
@@ -99,6 +99,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return convertFrom(type, bytes, 0, bytes.length); return convertFrom(type, bytes, 0, bytes.length);
} }
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final byte[] bytes, final int start, final int len) { public <T> T convertFrom(final Type type, final byte[] bytes, final int start, final int len) {
if (type == null) return null; if (type == null) return null;
final BsonReader in = readerPool.get(); final BsonReader in = readerPool.get();
@@ -109,16 +110,27 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return rs; return rs;
} }
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final InputStream in) { public <T> T convertFrom(final Type type, final InputStream in) {
if (type == null || in == null) return null; if (type == null || in == null) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in)); return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in));
} }
@Override
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) { public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
if (type == null || buffers.length < 1) return null; if (type == null || buffers.length < 1) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(buffers)); return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader((ConvertMask) null, buffers));
} }
@Override
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) {
if (type == null || buffers.length < 1) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(mask, buffers));
}
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final BsonReader reader) { public <T> T convertFrom(final Type type, final BsonReader reader) {
if (type == null) return null; if (type == null) return null;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -127,6 +139,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
} }
//------------------------------ convertTo ----------------------------------------------------------- //------------------------------ convertTo -----------------------------------------------------------
@Override
public byte[] convertTo(final Object value) { public byte[] convertTo(final Object value) {
if (value == null) { if (value == null) {
final BsonWriter out = writerPool.get().tiny(tiny); final BsonWriter out = writerPool.get().tiny(tiny);
@@ -138,6 +151,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return convertTo(value.getClass(), value); return convertTo(value.getClass(), value);
} }
@Override
public byte[] convertTo(final Type type, final Object value) { public byte[] convertTo(final Type type, final Object value) {
if (type == null) return null; if (type == null) return null;
final BsonWriter out = writerPool.get().tiny(tiny); final BsonWriter out = writerPool.get().tiny(tiny);
@@ -147,6 +161,16 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return result; return result;
} }
@Override
public byte[] convertMapTo(final Object... values) {
if (values == null) return null;
final BsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
byte[] result = out.toArray();
writerPool.offer(out);
return result;
}
public void convertTo(final OutputStream out, final Object value) { public void convertTo(final OutputStream out, final Object value) {
if (value == null) { if (value == null) {
new BsonStreamWriter(tiny, out).writeNull(); new BsonStreamWriter(tiny, out).writeNull();
@@ -164,6 +188,27 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
} }
} }
public void convertMapTo(final OutputStream out, final Object... values) {
if (values == null) {
new BsonStreamWriter(tiny, out).writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(new BsonStreamWriter(tiny, out), values);
}
}
@Override
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
if (supplier == null) return null;
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
if (value == null) {
out.writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(out, value);
}
return out.toBuffers();
}
@Override
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) { public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
if (supplier == null || type == null) return null; if (supplier == null || type == null) return null;
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier); BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
@@ -175,13 +220,14 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return out.toBuffers(); return out.toBuffers();
} }
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) { @Override
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
if (supplier == null) return null; if (supplier == null) return null;
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier); BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
if (value == null) { if (values == null) {
out.writeNull(); out.writeNull();
} else { } else {
factory.loadEncoder(value.getClass()).convertTo(out, value); ((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
} }
return out.toBuffers(); return out.toBuffers();
} }
@@ -199,6 +245,14 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
factory.loadEncoder(type).convertTo(writer, value); factory.loadEncoder(type).convertTo(writer, value);
} }
public void convertMapTo(final BsonWriter writer, final Object... values) {
if (values == null) {
writer.writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
}
}
public BsonWriter convertToWriter(final Object value) { public BsonWriter convertToWriter(final Object value) {
if (value == null) return null; if (value == null) return null;
return convertToWriter(value.getClass(), value); return convertToWriter(value.getClass(), value);
@@ -211,4 +265,9 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return out; return out;
} }
public BsonWriter convertMapToWriter(final Object... values) {
final BsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
return out;
}
} }

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) {
@@ -99,6 +87,7 @@ public class BsonReader extends Reader {
* 跳过属性的值 * 跳过属性的值
*/ */
@Override @Override
@SuppressWarnings("unchecked")
public final void skipValue() { public final void skipValue() {
if (typeval == 0) return; if (typeval == 0) return;
final byte val = this.typeval; final byte val = this.typeval;
@@ -164,7 +153,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 +162,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 +212,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 +261,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

@@ -21,6 +21,7 @@ class BsonStreamReader extends BsonByteBufferReader {
private byte currByte; private byte currByte;
protected BsonStreamReader(InputStream in) { protected BsonStreamReader(InputStream in) {
super((ConvertMask) null);
this.in = in; this.in = in;
} }

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

@@ -0,0 +1,44 @@
/*
* 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.SimpledCoder;
import org.redkale.convert.Writer;
import org.redkale.convert.Reader;
import java.math.BigDecimal;
import org.redkale.util.Utility;
/**
* BigDecimal 的SimpledCoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class BigDecimalSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, BigDecimal> {
public static final BigDecimalSimpledCoder instance = new BigDecimalSimpledCoder();
@Override
public void convertTo(W out, BigDecimal value) {
if (value == null) {
out.writeNull();
return;
}
out.writeSmallString(value.toString());
}
@Override
public BigDecimal convertFrom(R in) {
String value = in.readSmallString();
if (value == null) return null;
return new BigDecimal(Utility.charArray(value));
}
}

View File

@@ -0,0 +1,70 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import java.nio.ByteBuffer;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* ByteBuffer 的SimpledCoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class ByteBufferSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, ByteBuffer> {
public static final ByteBufferSimpledCoder instance = new ByteBufferSimpledCoder();
@Override
public void convertTo(W out, ByteBuffer value) {
if (value == null) {
out.writeNull();
return;
}
out.writeArrayB(value.remaining());
boolean flag = false;
for (byte v : value.array()) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
}
out.writeArrayE();
}
@Override
public ByteBuffer convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
while (in.hasNext()) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readByte();
}
in.readArrayE();
return ByteBuffer.wrap(data, 0, size);
} else {
byte[] values = new byte[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readByte();
}
in.readArrayE();
return ByteBuffer.wrap(values);
}
}
}

View File

@@ -32,7 +32,7 @@ public final class DateSimpledCoder<R extends Reader, W extends Writer> extends
@Override @Override
public Date convertFrom(R in) { public Date convertFrom(R in) {
long t = in.readLong(); long t = in.readLong();
return t == 0 ? null : new Date(); return t == 0 ? null : new Date(t);
} }
} }

View File

@@ -0,0 +1,41 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import java.io.File;
import org.redkale.convert.*;
/**
* 文件 的SimpledCoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
public static final PatternSimpledCoder instance = new PatternSimpledCoder();
@Override
public void convertTo(W out, File value) {
if (value == null) {
out.writeNull();
} else {
out.writeString(value.getPath());
}
}
@Override
public File convertFrom(R in) {
String value = in.readString();
if (value == null) return null;
return new File(value);
}
}

View File

@@ -20,6 +20,7 @@ import java.net.*;
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
@SuppressWarnings("unchecked")
public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetAddress> { public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetAddress> {
public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder(); public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder();
@@ -50,6 +51,7 @@ public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> e
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
@SuppressWarnings("unchecked")
public final static class InetSocketAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetSocketAddress> { public final static class InetSocketAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetSocketAddress> {
public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder(); public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder();

View File

@@ -37,8 +37,8 @@ public class TypeSimpledCoder<R extends Reader, W extends Writer> extends Simple
String str = in.readSmallString(); String str = in.readSmallString();
if (str == null) return null; if (str == null) return null;
try { try {
return Class.forName(str); return Thread.currentThread().getContextClassLoader().loadClass(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格式
* *
@@ -28,7 +29,10 @@ public class JsonByteBufferReader extends JsonReader {
private ByteBuffer currentBuffer; private ByteBuffer currentBuffer;
protected JsonByteBufferReader(ByteBuffer... buffers) { protected ConvertMask mask;
protected JsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) {
this.mask = mask;
this.buffers = buffers; this.buffers = buffers;
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
} }
@@ -40,19 +44,20 @@ public class JsonByteBufferReader extends JsonReader {
this.currentChar = 0; this.currentChar = 0;
this.currentBuffer = null; this.currentBuffer = null;
this.buffers = null; this.buffers = null;
this.mask = null;
return false; return false;
} }
protected byte nextByte() { protected byte nextByte() {
if (this.currentBuffer.hasRemaining()) { if (this.currentBuffer.hasRemaining()) {
this.position++; this.position++;
return this.currentBuffer.get(); return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
} }
for (;;) { for (;;) {
this.currentBuffer = this.buffers[++this.currentIndex]; this.currentBuffer = this.buffers[++this.currentIndex];
if (this.currentBuffer.hasRemaining()) { if (this.currentBuffer.hasRemaining()) {
this.position++; this.position++;
return this.currentBuffer.get(); return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
} }
} }
} }
@@ -157,7 +162,7 @@ public class JsonByteBufferReader extends JsonReader {
public final boolean hasNext() { public final boolean hasNext() {
char ch = nextGoodChar(); char ch = nextGoodChar();
if (ch == ',') return true; if (ch == ',') return true;
if (ch == '}' || ch == ']') return false; if (ch == '}' || ch == ']' || ch == 0) return false;
backChar(ch); // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取 backChar(ch); // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
return true; return true;
} }
@@ -248,6 +253,7 @@ public class JsonByteBufferReader extends JsonReader {
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")"); throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")");
} }
} else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 包含 0 } else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 包含 0
backChar(ch);
break; break;
} else { } else {
sb.append(ch); sb.append(ch);

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

@@ -21,7 +21,7 @@ import org.redkale.util.*;
* @author zhangjx * @author zhangjx
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class JsonConvert extends Convert<JsonReader, JsonWriter> { public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.LinkedHashMap<String, String>>() { public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.LinkedHashMap<String, String>>() {
}.getType(); }.getType();
@@ -48,7 +48,7 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
//------------------------------ reader ----------------------------------------------------------- //------------------------------ reader -----------------------------------------------------------
public JsonReader pollJsonReader(final ByteBuffer... buffers) { public JsonReader pollJsonReader(final ByteBuffer... buffers) {
return new JsonByteBufferReader(buffers); return new JsonByteBufferReader((ConvertMask) null, buffers);
} }
public JsonReader pollJsonReader(final InputStream in) { public JsonReader pollJsonReader(final InputStream in) {
@@ -109,9 +109,16 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
return (T) factory.loadDecoder(type).convertFrom(new JsonStreamReader(in)); return (T) factory.loadDecoder(type).convertFrom(new JsonStreamReader(in));
} }
@Override
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) { public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
if (type == null || buffers == null || buffers.length == 0) return null; if (type == null || buffers == null || buffers.length == 0) return null;
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader(buffers)); return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers));
}
@Override
public <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) {
if (type == null || buffers == null || buffers.length == 0) return null;
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader(mask, buffers));
} }
public <T> T convertFrom(final Type type, final JsonReader reader) { public <T> T convertFrom(final Type type, final JsonReader reader) {
@@ -122,11 +129,13 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
} }
//------------------------------ convertTo ----------------------------------------------------------- //------------------------------ convertTo -----------------------------------------------------------
@Override
public String convertTo(final Object value) { public String convertTo(final Object value) {
if (value == null) return "null"; if (value == null) return "null";
return convertTo(value.getClass(), value); return convertTo(value.getClass(), value);
} }
@Override
public String convertTo(final Type type, final Object value) { public String convertTo(final Type type, final Object value) {
if (type == null) return null; if (type == null) return null;
if (value == null) return "null"; if (value == null) return "null";
@@ -137,6 +146,16 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
return result; return result;
} }
@Override
public String convertMapTo(final Object... values) {
if (values == null) return "null";
final JsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
String result = out.toString();
writerPool.offer(out);
return result;
}
public void convertTo(final OutputStream out, final Object value) { public void convertTo(final OutputStream out, final Object value) {
if (value == null) { if (value == null) {
new JsonStreamWriter(tiny, out).writeNull(); new JsonStreamWriter(tiny, out).writeNull();
@@ -154,6 +173,15 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
} }
} }
public void convertMapTo(final OutputStream out, final Object... values) {
if (values == null) {
new JsonStreamWriter(tiny, out).writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(new JsonStreamWriter(tiny, out), values);
}
}
@Override
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) { public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
if (supplier == null) return null; if (supplier == null) return null;
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier); JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
@@ -165,6 +193,7 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
return out.toBuffers(); return out.toBuffers();
} }
@Override
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) { public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
if (supplier == null || type == null) return null; if (supplier == null || type == null) return null;
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier); JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
@@ -176,6 +205,18 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
return out.toBuffers(); return out.toBuffers();
} }
@Override
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
if (supplier == null) return null;
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
if (values == null) {
out.writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
}
return out.toBuffers();
}
public void convertTo(final JsonWriter writer, final Object value) { public void convertTo(final JsonWriter writer, final Object value) {
if (value == null) { if (value == null) {
writer.writeNull(); writer.writeNull();
@@ -193,6 +234,14 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
} }
} }
public void convertMapTo(final JsonWriter writer, final Object... values) {
if (values == null) {
writer.writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
}
}
public JsonWriter convertToWriter(final Object value) { public JsonWriter convertToWriter(final Object value) {
if (value == null) return null; if (value == null) return null;
return convertToWriter(value.getClass(), value); return convertToWriter(value.getClass(), value);
@@ -204,4 +253,10 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
factory.loadEncoder(type).convertTo(out, value); factory.loadEncoder(type).convertTo(out, value);
return out; return out;
} }
public JsonWriter convertMapToWriter(final Object... values) {
final JsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
return out;
}
} }

View File

@@ -10,15 +10,17 @@ 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
* *
* @author zhangjx * @author zhangjx
*/ */
@SuppressWarnings("unchecked")
public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> { public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny")); private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
@@ -29,6 +31,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
@@ -403,6 +404,7 @@ public class JsonReader extends Reader {
@Override @Override
public final DeMember readFieldName(final DeMember[] members) { public final DeMember readFieldName(final DeMember[] members) {
final String exceptedfield = this.readSmallString(); final String exceptedfield = this.readSmallString();
if(exceptedfield == null) return null;
final int len = members.length; final int len = members.length;
if (this.fieldIndex >= len) this.fieldIndex = 0; if (this.fieldIndex >= len) this.fieldIndex = 0;
for (int k = this.fieldIndex; k < len; k++) { for (int k = this.fieldIndex; k < len; k++) {

View File

@@ -19,6 +19,7 @@ class JsonStreamReader extends JsonByteBufferReader {
private InputStream in; private InputStream in;
protected JsonStreamReader(InputStream in) { protected JsonStreamReader(InputStream in) {
super((ConvertMask) null);
this.in = in; this.in = in;
} }

View File

@@ -11,6 +11,7 @@ import java.nio.ByteBuffer;
import java.nio.channels.*; import java.nio.channels.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* *
@@ -25,6 +26,12 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
protected Object subobject; //用于存储绑定在Connection上的对象 同attributes 只绑定单个对象时尽量使用subobject而非attributes protected Object subobject; //用于存储绑定在Connection上的对象 同attributes 只绑定单个对象时尽量使用subobject而非attributes
//关闭数
AtomicLong closedCounter = new AtomicLong();
//在线数
AtomicLong livingCounter = new AtomicLong();
public abstract boolean isTCP(); public abstract boolean isTCP();
public abstract SocketAddress getRemoteAddress(); public abstract SocketAddress getRemoteAddress();
@@ -43,7 +50,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
write(srcs, 0, srcs.length, attachment, handler); write(srcs, 0, srcs.length, attachment, handler);
} }
protected abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler); public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
public void dispose() {//同close 只是去掉throws IOException public void dispose() {//同close 只是去掉throws IOException
try { try {
@@ -54,6 +61,14 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
@Override @Override
public void close() throws IOException { public void close() throws IOException {
if (closedCounter != null) {
closedCounter.incrementAndGet();
closedCounter = null;
}
if (livingCounter != null) {
livingCounter.decrementAndGet();
livingCounter = null;
}
if (attributes == null) return; if (attributes == null) return;
try { try {
for (Object obj : attributes.values()) { for (Object obj : attributes.values()) {
@@ -107,11 +122,12 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
* @param group 连接AsynchronousChannelGroup * @param group 连接AsynchronousChannelGroup
* @param readTimeoutSecond0 读取超时秒数 * @param readTimeoutSecond0 读取超时秒数
* @param writeTimeoutSecond0 写入超时秒数 * @param writeTimeoutSecond0 写入超时秒数
*
* @return 连接 * @return 连接
* @throws java.io.IOException 异常 * @throws java.io.IOException 异常
*/ */
public static AsyncConnection create(final String protocol, final AsynchronousChannelGroup group, final SocketAddress address, public static AsyncConnection create(final String protocol, final AsynchronousChannelGroup group, final SocketAddress address,
final int readTimeoutSecond0, final int writeTimeoutSecond0) throws IOException { final int readTimeoutSecond0, final int writeTimeoutSecond0) throws IOException {
if ("TCP".equalsIgnoreCase(protocol)) { if ("TCP".equalsIgnoreCase(protocol)) {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group); AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group);
try { try {
@@ -143,7 +159,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
private final boolean client; private final boolean client;
public BIOUDPAsyncConnection(final DatagramChannel ch, SocketAddress addr, public BIOUDPAsyncConnection(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) { final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
this.channel = ch; this.channel = ch;
this.client = client0; this.client = client0;
this.readTimeoutSecond = readTimeoutSecond0; this.readTimeoutSecond = readTimeoutSecond0;
@@ -186,7 +202,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
} }
@Override @Override
protected <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) { public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
try { try {
int rs = 0; int rs = 0;
for (int i = offset; i < offset + length; i++) { for (int i = offset; i < offset + length; i++) {
@@ -213,7 +229,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
public Future<Integer> read(ByteBuffer dst) { public Future<Integer> read(ByteBuffer dst) {
try { try {
int rs = channel.read(dst); int rs = channel.read(dst);
return new SimpleFuture(rs); return CompletableFuture.completedFuture(rs);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -233,7 +249,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
public Future<Integer> write(ByteBuffer src) { public Future<Integer> write(ByteBuffer src) {
try { try {
int rs = channel.send(src, remoteAddress); int rs = channel.send(src, remoteAddress);
return new SimpleFuture(rs); return CompletableFuture.completedFuture(rs);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -257,45 +273,10 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
} }
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr, public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) { final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
return new BIOUDPAsyncConnection(ch, addr, client0, readTimeoutSecond0, writeTimeoutSecond0); return new BIOUDPAsyncConnection(ch, addr, client0, readTimeoutSecond0, writeTimeoutSecond0);
} }
private static class SimpleFuture implements Future<Integer> {
private final int rs;
public SimpleFuture(int rs) {
this.rs = rs;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return true;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return true;
}
@Override
public Integer get() throws InterruptedException, ExecutionException {
return rs;
}
@Override
public Integer get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return rs;
}
}
private static class BIOTCPAsyncConnection extends AsyncConnection { private static class BIOTCPAsyncConnection extends AsyncConnection {
private int readTimeoutSecond; private int readTimeoutSecond;
@@ -372,7 +353,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
} }
@Override @Override
protected <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) { public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
try { try {
int rs = 0; int rs = 0;
for (int i = offset; i < offset + length; i++) { for (int i = offset; i < offset + length; i++) {
@@ -398,7 +379,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
public Future<Integer> read(ByteBuffer dst) { public Future<Integer> read(ByteBuffer dst) {
try { try {
int rs = readChannel.read(dst); int rs = readChannel.read(dst);
return new SimpleFuture(rs); return CompletableFuture.completedFuture(rs);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -418,7 +399,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
public Future<Integer> write(ByteBuffer src) { public Future<Integer> write(ByteBuffer src) {
try { try {
int rs = writeChannel.write(src); int rs = writeChannel.write(src);
return new SimpleFuture(rs); return CompletableFuture.completedFuture(rs);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -440,6 +421,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
* 通常用于 ssl socket * 通常用于 ssl socket
* *
* @param socket Socket对象 * @param socket Socket对象
*
* @return 连接对象 * @return 连接对象
*/ */
public static AsyncConnection create(final Socket socket) { public static AsyncConnection create(final Socket socket) {

View File

@@ -14,50 +14,63 @@ import java.util.logging.*;
import org.redkale.convert.bson.*; import org.redkale.convert.bson.*;
import org.redkale.convert.json.*; import org.redkale.convert.json.*;
import org.redkale.util.*; import org.redkale.util.*;
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;
protected final ExecutorService executor; //Server的线程池
protected final ThreadPoolExecutor 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; public Context(long serverStartTime, Logger logger, ThreadPoolExecutor executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,
final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final int readTimeoutSecond, final int writeTimeoutSecond) {
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 readTimeoutSecond, final int writeTimeoutSecond) {
this.serverStartTime = serverStartTime; this.serverStartTime = serverStartTime;
this.logger = logger; this.logger = logger;
this.executor = executor; this.executor = executor;
@@ -68,7 +81,6 @@ public class Context {
this.charset = UTF8.equals(charset) ? null : charset; this.charset = UTF8.equals(charset) ? null : charset;
this.address = address; this.address = address;
this.prepare = prepare; this.prepare = prepare;
this.watch = watch;
this.readTimeoutSecond = readTimeoutSecond; this.readTimeoutSecond = readTimeoutSecond;
this.writeTimeoutSecond = writeTimeoutSecond; this.writeTimeoutSecond = writeTimeoutSecond;
this.jsonFactory = JsonFactory.root(); this.jsonFactory = JsonFactory.root();
@@ -91,8 +103,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() {
@@ -111,6 +127,13 @@ public class Context {
bufferPool.offer(buffer); bufferPool.offer(buffer);
} }
public void offerBuffer(ByteBuffer... buffers) {
if (buffers == null) return;
for (ByteBuffer buffer : buffers) {
bufferPool.offer(buffer);
}
}
public Logger getLogger() { public Logger getLogger() {
return logger; return logger;
} }

View File

@@ -0,0 +1,44 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net;
import java.io.IOException;
import javax.annotation.Priority;
import org.redkale.util.*;
/**
* 协议拦截器类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <C> Context的子类型
* @param <R> Request的子类型
* @param <P> Response的子类型
*/
public abstract class Filter<C extends Context, R extends Request<C>, P extends Response<C, R>> implements Comparable {
AnyValue _conf; //当前Filter的配置
Filter<C, R, P> _next; //下一个Filter
public void init(C context, AnyValue config) {
}
public abstract void doFilter(R request, P response) throws IOException;
public void destroy(C context, AnyValue config) {
}
@Override
public final int compareTo(Object o) {
if (!(o instanceof Filter)) return 1;
Priority p1 = this.getClass().getAnnotation(Priority.class);
Priority p2 = o.getClass().getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
}
}

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

@@ -10,10 +10,14 @@ import java.nio.*;
import java.nio.channels.*; import java.nio.channels.*;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
import java.util.function.Predicate;
import java.util.logging.*; 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,10 +35,179 @@ 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<>();
private final List<Filter<C, R, P>> filters = new ArrayList<>();
protected Filter<C, R, P> headFilter;
protected void putServlet(S servlet) {
synchronized (lock1) {
Set<S> newservlets = new HashSet<>(servlets);
newservlets.add(servlet);
this.servlets = newservlets;
}
}
protected void removeServlet(S servlet) {
synchronized (lock1) {
Set<S> newservlets = new HashSet<>(servlets);
newservlets.remove(servlet);
this.servlets = newservlets;
}
}
public boolean containsServlet(Class<? extends S> servletClass) {
synchronized (lock1) {
for (S servlet : new HashSet<>(servlets)) {
if (servlet.getClass().equals(servletClass)) return true;
}
return false;
}
}
public boolean containsServlet(String servletClassName) {
synchronized (lock1) {
for (S servlet : new HashSet<>(servlets)) {
if (servlet.getClass().getName().equals(servletClassName)) return true;
}
return false;
}
}
protected void putMapping(K key, S servlet) {
synchronized (lock2) {
Map<K, S> newmappings = new HashMap<>(mappings);
newmappings.put(key, servlet);
this.mappings = newmappings;
}
}
protected void removeMapping(K key) {
synchronized (lock2) {
if (mappings.containsKey(key)) {
Map<K, S> newmappings = new HashMap<>(mappings);
newmappings.remove(key);
this.mappings = newmappings;
}
}
}
protected void removeMapping(S servlet) {
synchronized (lock2) {
List<K> keys = new ArrayList<>();
Map<K, S> newmappings = new HashMap<>(mappings);
for (Map.Entry<K, S> en : newmappings.entrySet()) {
if (en.getValue().equals(servlet)) {
keys.add(en.getKey());
}
}
for (K key : keys) newmappings.remove(key);
this.mappings = newmappings;
}
}
protected S mappingServlet(K key) {
return mappings.get(key);
}
@Override
@SuppressWarnings("unchecked")
public void init(C context, AnyValue config) {
synchronized (filters) {
if (!filters.isEmpty()) {
Collections.sort(filters);
for (Filter<C, R, P> filter : filters) {
filter.init(context, config);
}
this.headFilter = filters.get(0);
Filter<C, R, P> filter = this.headFilter;
for (int i = 1; i < filters.size(); i++) {
filter._next = filters.get(i);
filter = filter._next;
}
}
}
}
@Override
@SuppressWarnings("unchecked")
public void destroy(C context, AnyValue config) {
synchronized (filters) {
if (!filters.isEmpty()) {
for (Filter filter : filters) {
filter.destroy(context, config);
}
}
}
}
@SuppressWarnings("unchecked")
public void addFilter(Filter<C, R, P> filter, AnyValue conf) {
filter._conf = conf;
synchronized (filters) {
this.filters.add(filter);
Collections.sort(this.filters);
}
}
public <T extends Filter<C, R, P>> T removeFilter(Class<T> filterClass) {
return removeFilter(f -> filterClass.equals(f.getClass()));
}
public boolean containsFilter(Class<? extends Filter> filterClass) {
if (this.headFilter == null || filterClass == null) return false;
Filter filter = this.headFilter;
do {
if (filter.getClass().equals(filterClass)) return true;
} while ((filter = filter._next) != null);
return false;
}
public boolean containsFilter(String filterClassName) {
if (this.headFilter == null || filterClassName == null) return false;
Filter filter = this.headFilter;
do {
if (filter.getClass().getName().equals(filterClassName)) return true;
} while ((filter = filter._next) != null);
return false;
}
@SuppressWarnings("unchecked")
public <T extends Filter<C, R, P>> T removeFilter(Predicate<T> predicate) {
if (this.headFilter == null || predicate == null) return null;
synchronized (filters) {
Filter filter = this.headFilter;
Filter prev = null;
do {
if (predicate.test((T) filter)) break;
prev = filter;
} while ((filter = filter._next) != null);
if (filter != null) {
if (prev == null) {
this.headFilter = filter._next;
} else {
prev._next = filter._next;
}
filter._next = null;
this.filters.remove(filter);
}
return (T) filter;
}
}
@SuppressWarnings("unchecked")
public <T extends Filter<C, R, P>> List<T> getFilters() {
return (List) new ArrayList<>(filters);
}
@SuppressWarnings("unchecked")
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings); public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
public final void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException { public final void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
@@ -47,7 +220,9 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
} else if (rs == 0) { } else if (rs == 0) {
response.context.offerBuffer(buffer); response.context.offerBuffer(buffer);
request.prepare(); request.prepare();
this.execute(request, response); response.filter = this.headFilter;
response.servlet = this;
response.nextEvent();
} else { } else {
buffer.clear(); buffer.clear();
final AtomicInteger ai = new AtomicInteger(rs); final AtomicInteger ai = new AtomicInteger(rs);
@@ -64,7 +239,9 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
response.context.offerBuffer(buffer); response.context.offerBuffer(buffer);
request.prepare(); request.prepare();
try { try {
execute(request, response); response.filter = PrepareServlet.this.headFilter;
response.servlet = PrepareServlet.this;
response.nextEvent();
} catch (Exception e) { } catch (Exception e) {
illRequestCounter.incrementAndGet(); illRequestCounter.incrementAndGet();
response.finish(true); response.finish(true);
@@ -92,7 +269,7 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
servlet._conf = conf; servlet._conf = conf;
} }
public Set<S> getServlets() { public List<S> getServlets() {
return new LinkedHashSet<>(servlets); return new ArrayList<>(servlets);
} }
} }

View File

@@ -11,14 +11,27 @@ import java.nio.ByteBuffer;
import java.nio.channels.*; import java.nio.channels.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* 协议底层Server
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public abstract class ProtocolServer { public abstract class ProtocolServer {
//创建数
protected final AtomicLong createCounter = new AtomicLong();
//关闭数
protected final AtomicLong closedCounter = new AtomicLong();
//在线数
protected final AtomicLong livingCounter = new AtomicLong();
public abstract void open() throws IOException; public abstract void open() throws IOException;
public abstract void bind(SocketAddress local, int backlog) throws IOException; public abstract void bind(SocketAddress local, int backlog) throws IOException;
@@ -33,6 +46,18 @@ public abstract class ProtocolServer {
public abstract AsynchronousChannelGroup getChannelGroup(); public abstract AsynchronousChannelGroup getChannelGroup();
public long getCreateCount() {
return createCounter.longValue();
}
public long getClosedCount() {
return closedCounter.longValue();
}
public long getLivingCount() {
return livingCounter.longValue();
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
public static ProtocolServer create(String protocol, Context context) { public static ProtocolServer create(String protocol, Context context) {
if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context); if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context);
@@ -91,7 +116,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);
} }
@@ -116,6 +141,20 @@ public abstract class ProtocolServer {
return null; return null;
} }
@Override
public long getCreateCount() {
return -1;
}
@Override
public long getClosedCount() {
return -1;
}
@Override
public long getLivingCount() {
return -1;
}
} }
private static final class ProtocolTCPServer extends ProtocolServer { private static final class ProtocolTCPServer extends ProtocolServer {
@@ -159,7 +198,12 @@ 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)); createCounter.incrementAndGet();
livingCounter.incrementAndGet();
AsyncConnection conn = AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond);
conn.livingCounter = livingCounter;
conn.closedCounter = closedCounter;
context.submitAsync(new PrepareRunner(context, conn, 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
@@ -50,6 +51,7 @@ public abstract class Request<C extends Context> {
* 返回值Integer.MIN_VALUE: 帧数据; -1数据不合法 0解析完毕 &gt;0: 需再读取的字节数。 * 返回值Integer.MIN_VALUE: 帧数据; -1数据不合法 0解析完毕 &gt;0: 需再读取的字节数。
* *
* @param buffer ByteBuffer对象 * @param buffer ByteBuffer对象
*
* @return 缺少的字节数 * @return 缺少的字节数
*/ */
protected abstract int readHeader(ByteBuffer buffer); protected abstract int readHeader(ByteBuffer buffer);
@@ -58,6 +60,7 @@ public abstract class Request<C extends Context> {
* 读取buffer并返回读取的有效数据长度 * 读取buffer并返回读取的有效数据长度
* *
* @param buffer ByteBuffer对象 * @param buffer ByteBuffer对象
*
* @return 有效数据长度 * @return 有效数据长度
*/ */
protected abstract int readBody(ByteBuffer buffer); protected abstract int readBody(ByteBuffer buffer);
@@ -81,8 +84,9 @@ public abstract class Request<C extends Context> {
return (T) properties.get(name); return (T) properties.get(name);
} }
@SuppressWarnings("unchecked")
protected <T> T removeProperty(String name) { protected <T> T removeProperty(String name) {
return (T)properties.remove(name); return (T) properties.remove(name);
} }
protected Map<String, Object> getProperties() { protected Map<String, Object> getProperties() {
@@ -99,8 +103,9 @@ public abstract class Request<C extends Context> {
return (T) attributes.get(name); return (T) attributes.get(name);
} }
@SuppressWarnings("unchecked")
public <T> T removeAttribute(String name) { public <T> T removeAttribute(String name) {
return (T)attributes.remove(name); return (T) attributes.remove(name);
} }
public Map<String, Object> getAttributes() { public Map<String, Object> getAttributes() {

View File

@@ -5,11 +5,14 @@
*/ */
package org.redkale.net; package org.redkale.net;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler; import java.nio.channels.CompletionHandler;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.logging.Level;
/** /**
* 协议响应对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -29,8 +32,14 @@ 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;
protected Filter<C, R, ? extends Response<C, R>> filter;
protected Servlet<C, R, ? extends Response<C, R>> servlet;
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() { private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
@Override @Override
@@ -54,29 +63,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);
} }
@@ -108,15 +114,17 @@ public abstract class Response<C extends Context, R extends Request<C>> {
try { try {
recycleListener.accept(request, this); recycleListener.accept(request, this);
} catch (Exception e) { } catch (Exception e) {
System.err.println(request); context.logger.log(Level.WARNING, "Response.recycleListener error, request = " + request, e);
e.printStackTrace();
} }
recycleListener = null; recycleListener = null;
} }
this.output = null;
this.filter = null;
this.servlet = 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();
@@ -139,34 +147,87 @@ public abstract class Response<C extends Context, R extends Request<C>> {
this.request.createtime = System.currentTimeMillis(); this.request.createtime = System.currentTimeMillis();
} }
public void setRecycleListener(BiConsumer<R, Response<C, R>> recycleListener) { protected void setFilter(Filter<C, R, Response<C, R>> filter) {
this.filter = filter;
}
protected void thenEvent(Servlet servlet) {
this.servlet = servlet;
}
@SuppressWarnings("unchecked")
public void nextEvent() throws IOException {
if (this.filter != null) {
Filter runner = this.filter;
this.filter = this.filter._next;
runner.doFilter(request, this);
return;
}
if (this.servlet != null) {
Servlet s = this.servlet;
this.servlet = null;
s.execute(request, this);
}
}
public void recycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
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

@@ -6,7 +6,6 @@
package org.redkale.net; package org.redkale.net;
import java.io.*; import java.io.*;
import java.lang.reflect.Method;
import java.net.*; import java.net.*;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.*; import java.text.*;
@@ -14,8 +13,7 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.redkale.util.AnyValue; import org.redkale.util.*;
import org.redkale.watch.WatchFactory;
/** /**
* *
@@ -39,9 +37,6 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
//服务的启动时间 //服务的启动时间
protected final long serverStartTime; protected final long serverStartTime;
//监控对象
protected final WatchFactory watch;
//服务的名称 //服务的名称
protected String name; protected String name;
@@ -76,7 +71,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
protected int threads; protected int threads;
//线程池 //线程池
protected ExecutorService executor; protected ThreadPoolExecutor executor;
//ByteBuffer池大小 //ByteBuffer池大小
protected int bufferPoolSize; protected int bufferPoolSize;
@@ -93,11 +88,10 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
//IO写入 的超时秒数小于1视为不设置 //IO写入 的超时秒数小于1视为不设置
protected int writeTimeoutSecond; protected int writeTimeoutSecond;
protected Server(long serverStartTime, String protocol, PrepareServlet<K, C, R, P, S> servlet, final WatchFactory watch) { protected Server(long serverStartTime, String protocol, PrepareServlet<K, C, R, P, S> servlet) {
this.serverStartTime = serverStartTime; this.serverStartTime = serverStartTime;
this.protocol = protocol; this.protocol = protocol;
this.prepare = servlet; this.prepare = servlet;
this.watch = watch;
} }
public void init(final AnyValue config) throws Exception { public void init(final AnyValue config) throws Exception {
@@ -105,11 +99,12 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
this.config = config; this.config = config;
this.address = new InetSocketAddress(config.getValue("host", "0.0.0.0"), config.getIntValue("port", 80)); this.address = new InetSocketAddress(config.getValue("host", "0.0.0.0"), config.getIntValue("port", 80));
this.charset = Charset.forName(config.getValue("charset", "UTF-8")); this.charset = Charset.forName(config.getValue("charset", "UTF-8"));
this.backlog = config.getIntValue("backlog", 8 * 1024);
this.readTimeoutSecond = config.getIntValue("readTimeoutSecond", 0); this.readTimeoutSecond = config.getIntValue("readTimeoutSecond", 0);
this.writeTimeoutSecond = config.getIntValue("writeTimeoutSecond", 0); this.writeTimeoutSecond = config.getIntValue("writeTimeoutSecond", 0);
this.maxbody = config.getIntValue("maxbody", 64 * 1024); this.backlog = parseLenth(config.getValue("backlog"), 8 * 1024);
this.bufferCapacity = config.getIntValue("bufferCapacity", 8 * 1024); this.maxbody = parseLenth(config.getValue("maxbody"), 64 * 1024);
int bufCapacity = parseLenth(config.getValue("bufferCapacity"), 8 * 1024);
this.bufferCapacity = bufCapacity < 256 ? 256 : bufCapacity;
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 16); this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 16);
this.bufferPoolSize = config.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 512); this.bufferPoolSize = config.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 512);
this.responsePoolSize = config.getIntValue("responsePoolSize", Runtime.getRuntime().availableProcessors() * 256); this.responsePoolSize = config.getIntValue("responsePoolSize", Runtime.getRuntime().availableProcessors() * 256);
@@ -118,13 +113,31 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
final AtomicInteger counter = new AtomicInteger(); final AtomicInteger counter = new AtomicInteger();
final Format f = createFormat(); final Format f = createFormat();
final String n = name; final String n = name;
this.executor = Executors.newFixedThreadPool(threads, (Runnable r) -> { this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threads, (Runnable r) -> {
Thread t = new WorkThread(executor, r); Thread t = new WorkThread(executor, r);
t.setName(n + "-ServletThread-" + f.format(counter.incrementAndGet())); t.setName(n + "-ServletThread-" + f.format(counter.incrementAndGet()));
return t; return t;
}); });
} }
protected static int parseLenth(String value, int defValue) {
if (value == null) return defValue;
value = value.toUpperCase().replace("B", "");
if (value.endsWith("G")) return Integer.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
if (value.endsWith("M")) return Integer.decode(value.replace("M", "")) * 1024 * 1024;
if (value.endsWith("K")) return Integer.decode(value.replace("K", "")) * 1024;
return Integer.decode(value);
}
protected static long parseLenth(String value, long defValue) {
if (value == null) return defValue;
value = value.toUpperCase().replace("B", "");
if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
if (value.endsWith("M")) return Long.decode(value.replace("M", "")) * 1024 * 1024;
if (value.endsWith("K")) return Long.decode(value.replace("K", "")) * 1024;
return Long.decode(value);
}
public void destroy(final AnyValue config) throws Exception { public void destroy(final AnyValue config) throws Exception {
this.prepare.destroy(context, config); this.prepare.destroy(context, config);
} }
@@ -153,6 +166,13 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
return this.context; return this.context;
} }
public void setThreads(int threads) {
int oldthreads = this.threads;
this.context.executor.setCorePoolSize(threads);
this.threads = threads;
logger.info("[" + Thread.currentThread().getName() + "] " + this.getClass().getSimpleName() + " change threads from " + oldthreads + " to " + threads);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void addServlet(S servlet, final Object attachment, AnyValue conf, K... mappings) { public void addServlet(S servlet, final Object attachment, AnyValue conf, K... mappings) {
this.prepare.addServlet(servlet, attachment, conf, mappings); this.prepare.addServlet(servlet, attachment, conf, mappings);
@@ -161,7 +181,6 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
public void start() throws IOException { public void start() throws IOException {
this.context = this.createContext(); this.context = this.createContext();
this.prepare.init(this.context, config); this.prepare.init(this.context, config);
if (this.watch != null) this.watch.inject(this.prepare);
this.serverChannel = ProtocolServer.create(this.protocol, context); this.serverChannel = ProtocolServer.create(this.protocol, context);
this.serverChannel.open(); this.serverChannel.open();
if (this.serverChannel.supportedOptions().contains(StandardSocketOptions.TCP_NODELAY)) { if (this.serverChannel.supportedOptions().contains(StandardSocketOptions.TCP_NODELAY)) {
@@ -190,6 +209,76 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
logger.info(this.getClass().getSimpleName() + " shutdown in " + e + " ms"); logger.info(this.getClass().getSimpleName() + " shutdown in " + e + " ms");
} }
/**
* 判断是否存在Filter
*
* @param <T> 泛型
* @param filterClass Filter类
*
* @return boolean
*/
public <T extends Filter> boolean containsFilter(Class<T> filterClass) {
return this.prepare.containsFilter(filterClass);
}
/**
* 判断是否存在Filter
*
* @param <T> 泛型
* @param filterClassName Filter类
*
* @return boolean
*/
public <T extends Filter> boolean containsFilter(String filterClassName) {
return this.prepare.containsFilter(filterClassName);
}
/**
* 判断是否存在Servlet
*
* @param servletClass Servlet类
*
* @return boolean
*/
public boolean containsServlet(Class<? extends S> servletClass) {
return this.prepare.containsServlet(servletClass);
}
/**
* 判断是否存在Servlet
*
* @param servletClassName Servlet类
*
* @return boolean
*/
public boolean containsServlet(String servletClassName) {
return this.prepare.containsServlet(servletClassName);
}
/**
* 销毁Servlet
*
* @param servlet Servlet
*/
public void destroyServlet(S servlet) {
servlet.destroy(context, this.prepare.getServletConf(servlet));
}
//创建数
public long getCreateConnectionCount() {
return serverChannel == null ? -1 : serverChannel.getCreateCount();
}
//关闭数
public long getClosedConnectionCount() {
return serverChannel == null ? -1 : serverChannel.getClosedCount();
}
//在线数
public long getLivingConnectionCount() {
return serverChannel == null ? -1 : serverChannel.getLivingCount();
}
protected Format createFormat() { protected Format createFormat() {
String sf = "0"; String sf = "0";
if (this.threads > 10) sf = "00"; if (this.threads > 10) sf = "00";
@@ -198,7 +287,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
return new DecimalFormat(sf); return new DecimalFormat(sf);
} }
public static URL[] loadLib(final Logger logger, final String lib) throws Exception { public static URL[] loadLib(final RedkaleClassLoader classLoader, final Logger logger, final String lib) throws Exception {
if (lib == null || lib.isEmpty()) return new URL[0]; if (lib == null || lib.isEmpty()) return new URL[0];
final Set<URL> set = new HashSet<>(); final Set<URL> set = new HashSet<>();
for (String s : lib.split(";")) { for (String s : lib.split(";")) {
@@ -216,17 +305,8 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
} }
} }
if (set.isEmpty()) return new URL[0]; if (set.isEmpty()) return new URL[0];
ClassLoader cl = Thread.currentThread().getContextClassLoader(); for (URL url : set) {
if (cl instanceof URLClassLoader) { classLoader.addURL(url);
URLClassLoader loader = (URLClassLoader) cl;
final Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
for (URL url : set) {
method.invoke(loader, url);
//if (logger != null) logger.log(Level.INFO, "Server found ClassPath({0})", url);
}
} else {
Thread.currentThread().setContextClassLoader(new URLClassLoader(set.toArray(new URL[set.size()]), cl));
} }
List<URL> list = new ArrayList<>(set); List<URL> list = new ArrayList<>(set);
Collections.sort(list, (URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile())); Collections.sort(list, (URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));

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

@@ -11,9 +11,9 @@ import java.nio.channels.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import org.redkale.convert.*;
import org.redkale.util.ObjectPool; import org.redkale.convert.json.JsonConvert;
import org.redkale.watch.WatchFactory; import org.redkale.util.*;
/** /**
* 传输客户端 * 传输客户端
@@ -44,82 +44,93 @@ 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;
protected final String protocol; protected final String protocol;
protected final WatchFactory watch;
protected final AsynchronousChannelGroup group; protected final AsynchronousChannelGroup group;
protected final InetSocketAddress clientAddress; protected final InetSocketAddress clientAddress;
protected InetSocketAddress[] remoteAddres = new InetSocketAddress[0]; protected TransportAddress[] transportAddres = new TransportAddress[0];
protected final ObjectPool<ByteBuffer> bufferPool; protected final ObjectPool<ByteBuffer> bufferPool;
//负载均衡策略
protected final TransportStrategy strategy;
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, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) { final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress,
this(name, DEFAULT_PROTOCOL, watch, kind, transportBufferPool, transportChannelGroup, clientAddress, addresses); final Collection<InetSocketAddress> addresses, final TransportStrategy strategy) {
this(name, DEFAULT_PROTOCOL, subprotocol, transportBufferPool, transportChannelGroup, clientAddress, addresses, strategy);
} }
public Transport(String name, String protocol, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool, public Transport(String name, String protocol, 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, final TransportStrategy strategy) {
this.name = name; this.name = name;
this.watch = watch; this.subprotocol = subprotocol == null ? "" : subprotocol.trim();
this.kind = kind == null ? "" : kind.trim();
this.protocol = protocol; this.protocol = protocol;
this.tcp = "TCP".equalsIgnoreCase(protocol); this.tcp = "TCP".equalsIgnoreCase(protocol);
this.group = transportChannelGroup; this.group = transportChannelGroup;
this.bufferPool = transportBufferPool; this.bufferPool = transportBufferPool;
this.clientAddress = clientAddress; this.clientAddress = clientAddress;
this.strategy = strategy;
updateRemoteAddresses(addresses); updateRemoteAddresses(addresses);
} }
public Transport(final Collection<Transport> transports) {
Transport first = null;
List<String> tmpgroup = new ArrayList<>();
for (Transport t : transports) {
if (first == null) first = t;
tmpgroup.add(t.name);
}
//必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name
this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";"));
this.watch = first.watch;
this.kind = first.kind;
this.protocol = first.protocol;
this.tcp = "TCP".equalsIgnoreCase(first.protocol);
this.group = first.group;
this.bufferPool = first.bufferPool;
this.clientAddress = first.clientAddress;
Set<InetSocketAddress> addrs = new HashSet<>();
transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses())));
updateRemoteAddresses(addrs);
}
public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) { public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) {
InetSocketAddress[] oldAddresses = this.remoteAddres; TransportAddress[] oldAddresses = this.transportAddres;
List<InetSocketAddress> list = new ArrayList<>(); List<TransportAddress> list = new ArrayList<>();
if (addresses != null) { if (addresses != null) {
for (InetSocketAddress addr : addresses) { for (InetSocketAddress addr : addresses) {
if (clientAddress != null && clientAddress.equals(addr)) continue; if (clientAddress != null && clientAddress.equals(addr)) continue;
list.add(addr); list.add(new TransportAddress(addr));
} }
} }
this.remoteAddres = list.toArray(new InetSocketAddress[list.size()]); this.transportAddres = list.toArray(new TransportAddress[list.size()]);
return oldAddresses;
InetSocketAddress[] rs = new InetSocketAddress[oldAddresses.length];
for (int i = 0; i < rs.length; i++) {
rs[i] = oldAddresses[i].getAddress();
}
return rs;
}
public final boolean addRemoteAddresses(final InetSocketAddress addr) {
if (addr == null) return false;
synchronized (this) {
if (this.transportAddres == null) {
this.transportAddres = new TransportAddress[]{new TransportAddress(addr)};
} else {
for (TransportAddress i : this.transportAddres) {
if (addr.equals(i.address)) return false;
}
this.transportAddres = Utility.append(transportAddres, new TransportAddress(addr));
}
return true;
}
}
public final boolean removeRemoteAddresses(InetSocketAddress addr) {
if (addr == null) return false;
if (this.transportAddres == null) return false;
synchronized (this) {
this.transportAddres = Utility.remove(transportAddres, new TransportAddress(addr));
}
return true;
} }
public String getName() { public String getName() {
return name; return name;
} }
public String getKind() { public String getSubprotocol() {
return kind; return subprotocol;
} }
public void close() { public void close() {
@@ -130,13 +141,25 @@ public final class Transport {
return clientAddress; return clientAddress;
} }
public TransportAddress[] getTransportAddresses() {
return transportAddres;
}
public InetSocketAddress[] getRemoteAddresses() { public InetSocketAddress[] getRemoteAddresses() {
return remoteAddres; InetSocketAddress[] rs = new InetSocketAddress[transportAddres.length];
for (int i = 0; i < rs.length; i++) {
rs[i] = transportAddres[i].getAddress();
}
return rs;
}
public ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> getAsyncConnectionPool() {
return connPool;
} }
@Override @Override
public String toString() { public String toString() {
return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteAddres = " + Arrays.toString(remoteAddres) + "}"; return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteAddres = " + Arrays.toString(transportAddres) + "}";
} }
public ByteBuffer pollBuffer() { public ByteBuffer pollBuffer() {
@@ -160,32 +183,57 @@ public final class Transport {
} }
public AsyncConnection pollConnection(SocketAddress addr) { public AsyncConnection pollConnection(SocketAddress addr) {
if (addr == null && remoteAddres.length == 1) addr = remoteAddres[0]; if (this.strategy != null) return strategy.pollConnection(addr, this);
if (addr == null && this.transportAddres.length == 1) addr = this.transportAddres[0].address;
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 && this.transportAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") have no remoteAddress list");
try { try {
if (tcp) { if (tcp) {
AsynchronousSocketChannel channel = null; AsynchronousSocketChannel channel = null;
if (rand) { //取地址 if (rand) { //取地址
for (int i = 0; i < remoteAddres.length; i++) { TransportAddress transportAddr;
addr = remoteAddres[i]; boolean tryed = false;
BlockingQueue<AsyncConnection> queue = connPool.get(addr); for (int i = 0; i < transportAddres.length; i++) {
if (queue != null && !queue.isEmpty()) { transportAddr = transportAddres[i];
addr = transportAddr.address;
if (!transportAddr.enable) continue;
final BlockingQueue<AsyncConnection> queue = transportAddr.conns;
if (!queue.isEmpty()) {
AsyncConnection conn; AsyncConnection conn;
while ((conn = queue.poll()) != null) { while ((conn = queue.poll()) != null) {
if (conn.isOpen()) return conn; if (conn.isOpen()) return conn;
} }
} }
tryed = true;
if (channel == null) { if (channel == null) {
channel = AsynchronousSocketChannel.open(group); channel = AsynchronousSocketChannel.open(group);
if (supportTcpNoDelay) channel.setOption(StandardSocketOptions.TCP_NODELAY, true); if (supportTcpNoDelay) channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
} }
try { try {
channel.connect(addr).get(2, TimeUnit.SECONDS); channel.connect(addr).get(2, TimeUnit.SECONDS);
transportAddr.enable = true;
break; break;
} catch (Exception iex) { } catch (Exception iex) {
iex.printStackTrace(); transportAddr.enable = false;
if (i == remoteAddres.length - 1) channel = null; channel = null;
}
}
if (channel == null && !tryed) {
for (int i = 0; i < transportAddres.length; i++) {
transportAddr = transportAddres[i];
addr = transportAddr.address;
if (channel == null) {
channel = AsynchronousSocketChannel.open(group);
if (supportTcpNoDelay) channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
}
try {
channel.connect(addr).get(2, TimeUnit.SECONDS);
transportAddr.enable = true;
break;
} catch (Exception iex) {
transportAddr.enable = false;
channel = null;
}
} }
} }
} else { } else {
@@ -196,7 +244,7 @@ public final class Transport {
if (channel == null) return null; if (channel == null) return null;
return AsyncConnection.create(channel, addr, 3000, 3000); return AsyncConnection.create(channel, addr, 3000, 3000);
} else { // UDP } else { // UDP
if (rand) addr = remoteAddres[0]; if (rand) addr = this.transportAddres[0].address;
DatagramChannel channel = DatagramChannel.open(); DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true); channel.configureBlocking(true);
channel.connect(addr); channel.connect(addr);
@@ -258,4 +306,54 @@ public final class Transport {
}); });
} }
public static class TransportAddress {
protected InetSocketAddress address;
protected volatile boolean enable;
protected final BlockingQueue<AsyncConnection> conns = new ArrayBlockingQueue<>(MAX_POOL_LIMIT);
public TransportAddress(InetSocketAddress address) {
this.address = address;
this.enable = true;
}
@java.beans.ConstructorProperties({"address", "enable"})
public TransportAddress(InetSocketAddress address, boolean enable) {
this.address = address;
this.enable = enable;
}
public InetSocketAddress getAddress() {
return address;
}
public boolean isEnable() {
return enable;
}
@ConvertColumn(ignore = true)
public BlockingQueue<AsyncConnection> getConns() {
return conns;
}
@Override
public int hashCode() {
return this.address.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final TransportAddress other = (TransportAddress) obj;
return this.address.equals(other.address);
}
public String toString() {
return JsonConvert.root().convertTo(this);
}
}
} }

View File

@@ -0,0 +1,189 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net;
import java.lang.ref.WeakReference;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import java.util.stream.Collectors;
import org.redkale.service.Service;
import org.redkale.util.ObjectPool;
/**
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class TransportFactory {
protected static final Logger logger = Logger.getLogger(TransportFactory.class.getSimpleName());
//传输端的线程池
protected final ExecutorService executor;
//传输端的ByteBuffer对象池
protected final ObjectPool<ByteBuffer> bufferPool;
//传输端的ChannelGroup
protected final AsynchronousChannelGroup channelGroup;
//每个地址对应的Group名
protected final Map<InetSocketAddress, String> groupAddrs = new HashMap<>();
//协议地址的Group集合
protected final Map<String, TransportGroupInfo> groupInfos = new HashMap<>();
protected final List<WeakReference<Service>> services = new CopyOnWriteArrayList<>();
//负载均衡策略
protected final TransportStrategy strategy;
public TransportFactory(ExecutorService executor, ObjectPool<ByteBuffer> bufferPool, AsynchronousChannelGroup channelGroup,
final TransportStrategy strategy) {
this.executor = executor;
this.bufferPool = bufferPool;
this.channelGroup = channelGroup;
this.strategy = strategy;
}
public TransportFactory(ExecutorService executor, ObjectPool<ByteBuffer> bufferPool, AsynchronousChannelGroup channelGroup) {
this(executor, bufferPool, channelGroup, null);
}
public String findGroupName(InetSocketAddress addr) {
if (addr == null) return null;
return groupAddrs.get(addr);
}
public TransportGroupInfo findGroupInfo(String group) {
if (group == null) return null;
return groupInfos.get(group);
}
public boolean addGroupInfo(String groupName, InetSocketAddress... addrs) {
addGroupInfo(new TransportGroupInfo(groupName, addrs));
return true;
}
public boolean removeGroupInfo(String groupName, InetSocketAddress addr) {
if (groupName == null || groupName.isEmpty() || addr == null) return false;
if (!groupName.equals(groupAddrs.get(addr))) return false;
TransportGroupInfo group = groupInfos.get(groupName);
if (group == null) return false;
group.removeAddress(addr);
groupAddrs.remove(addr);
return true;
}
public TransportFactory addGroupInfo(String name, Set<InetSocketAddress> addrs) {
addGroupInfo(new TransportGroupInfo(name, addrs));
return this;
}
public boolean addGroupInfo(TransportGroupInfo info) {
if (info == null) throw new RuntimeException("TransportGroupInfo can not null");
if (info.addresses == null) throw new RuntimeException("TransportGroupInfo.addresses can not null");
if (!checkName(info.name)) throw new RuntimeException("Transport.group.name only 0-9 a-z A-Z _ cannot begin 0-9");
TransportGroupInfo old = groupInfos.get(info.name);
if (old != null && !old.protocol.equals(info.protocol)) throw new RuntimeException("Transport.group.name repeat but protocol is different");
if (old != null && !old.subprotocol.equals(info.subprotocol)) throw new RuntimeException("Transport.group.name repeat but subprotocol is different");
for (InetSocketAddress addr : info.addresses) {
if (!groupAddrs.getOrDefault(addr, info.name).equals(info.name)) throw new RuntimeException(addr + " repeat but different group.name");
}
if (old == null) {
groupInfos.put(info.name, info);
} else {
old.putAddress(info.addresses);
}
for (InetSocketAddress addr : info.addresses) {
groupAddrs.put(addr, info.name);
}
return true;
}
public Transport loadSameGroupTransport(InetSocketAddress sncpAddress) {
return loadTransport(groupAddrs.get(sncpAddress), sncpAddress);
}
public Transport[] loadDiffGroupTransports(InetSocketAddress sncpAddress, final Set<String> diffGroups) {
if (diffGroups == null) return null;
final String sncpGroup = groupAddrs.get(sncpAddress);
final List<Transport> transports = new ArrayList<>();
for (String group : diffGroups) {
if (sncpGroup == null || !sncpGroup.equals(group)) {
transports.add(loadTransport(group, sncpAddress));
}
}
return transports.toArray(new Transport[transports.size()]);
}
public Transport loadRemoteTransport(InetSocketAddress sncpAddress, final Set<String> groups) {
if (groups == null) return null;
Set<InetSocketAddress> addresses = new HashSet<>();
TransportGroupInfo info = null;
for (String group : groups) {
info = groupInfos.get(group);
if (info == null) continue;
addresses.addAll(info.addresses);
}
if (info == null) return null;
if (sncpAddress != null) addresses.remove(sncpAddress);
return new Transport(groups.stream().sorted().collect(Collectors.joining(";")), info.protocol, info.subprotocol, this.bufferPool, this.channelGroup, sncpAddress, addresses, this.strategy);
}
private Transport loadTransport(final String groupName, InetSocketAddress sncpAddress) {
if (groupName == null) return null;
TransportGroupInfo info = groupInfos.get(groupName);
if (info == null) return null;
return new Transport(groupName, info.protocol, info.subprotocol, this.bufferPool, this.channelGroup, sncpAddress, info.addresses, this.strategy);
}
public ExecutorService getExecutor() {
return executor;
}
public List<TransportGroupInfo> getGroupInfos() {
return new ArrayList<>(this.groupInfos.values());
}
public void addSncpService(Service service) {
if (service == null) return;
services.add(new WeakReference<>(service));
}
public List<Service> getServices() {
List<Service> rs = new ArrayList<>();
for (WeakReference<Service> ref : services) {
Service service = ref.get();
if (service != null) rs.add(service);
}
return rs;
}
public void shutdownNow() {
try {
this.channelGroup.shutdownNow();
} catch (Exception e) {
logger.log(Level.FINER, "close transportChannelGroup erroneous", e);
}
}
private static boolean checkName(String name) { //不能含特殊字符
if (name.isEmpty()) return false;
if (name.charAt(0) >= '0' && name.charAt(0) <= '9') return false;
for (char ch : name.toCharArray()) {
if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //不能含特殊字符
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,127 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net;
import java.net.InetSocketAddress;
import java.util.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.util.Utility;
/**
* 协议地址组合对象, 对应application.xml 中 resources-&#62;group 节点信息
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class TransportGroupInfo {
protected String name; //地址
protected String protocol; //协议 取值范围: TCP、UDP
protected String subprotocol; //子协议,预留使用
protected Set<InetSocketAddress> addresses; //地址列表, 对应 resources-&#62;group-&#62;node节点信息
public TransportGroupInfo() {
}
public TransportGroupInfo(String name, InetSocketAddress... addrs) {
this(name, "TCP", "", Utility.ofSet(addrs));
}
public TransportGroupInfo(String name, Set<InetSocketAddress> addrs) {
this(name, "TCP", "", addrs);
}
public TransportGroupInfo(String name, String protocol, String subprotocol, InetSocketAddress... addrs) {
this(name, protocol, subprotocol, Utility.ofSet(addrs));
}
public TransportGroupInfo(String name, String protocol, String subprotocol, Set<InetSocketAddress> addrs) {
Objects.requireNonNull(name, "Transport.group.name can not null");
this.name = name;
this.protocol = protocol == null ? "TCP" : protocol;
this.subprotocol = subprotocol == null ? "" : subprotocol;
this.addresses = addrs;
}
public String getName() {
return name;
}
public void setName(String name) {
Objects.requireNonNull(name, "Transport.group.name can not null");
this.name = name;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol == null ? "TCP" : protocol;
}
public String getSubprotocol() {
return subprotocol;
}
public void setSubprotocol(String subprotocol) {
this.subprotocol = subprotocol == null ? "" : subprotocol;
this.subprotocol = subprotocol;
}
public Set<InetSocketAddress> getAddresses() {
return addresses;
}
public Set<InetSocketAddress> copyAddresses() {
return addresses == null ? null : new LinkedHashSet<>(addresses);
}
public void setAddresses(Set<InetSocketAddress> addresses) {
this.addresses = addresses;
}
public boolean containsAddress(InetSocketAddress addr) {
synchronized (this) {
if (this.addresses == null) return false;
return this.addresses.contains(addr);
}
}
public void removeAddress(InetSocketAddress addr) {
if (addr == null) return;
synchronized (this) {
if (this.addresses == null) return;
this.addresses.remove(addr);
}
}
public void putAddress(InetSocketAddress addr) {
if (addr == null) return;
synchronized (this) {
if (this.addresses == null) this.addresses = new HashSet<>();
this.addresses.add(addr);
}
}
public void putAddress(Set<InetSocketAddress> addrs) {
if (addrs == null) return;
synchronized (this) {
if (this.addresses == null) this.addresses = new HashSet<>();
this.addresses.addAll(addrs);
}
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}

View File

@@ -0,0 +1,21 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net;
import java.net.SocketAddress;
/**
* 远程请求的负载均衡策略
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public interface TransportStrategy {
public AsyncConnection pollConnection(SocketAddress addr, Transport transport);
}

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