1214 Commits
1.9.0 ... 2.6.0

Author SHA1 Message Date
Redkale
6e21fe56e9 Redkale 2.6.0 结束 2021-12-01 09:52:52 +08:00
Redkale
f0ac042b3c Update README.md 2021-10-18 20:58:14 +08:00
Redkale
13a4264488 Redkale 2.5.0 结束 2021-10-18 20:48:42 +08:00
redkale
7ffb65cc38 Redkale 2.4.0 结束 2021-10-18 13:19:30 +08:00
Redkale
2464c360c0 Redkale 2.4.0 结束 2021-06-06 19:06:05 +08:00
Redkale
1917ccf35c Redkale 2.3.0 结束 2021-04-09 00:28:57 +08:00
Redkale
4f9c14da97 2021-01-20 19:25:29 +08:00
Redkale
58e23c1b8c 2021-01-20 19:13:38 +08:00
Redkale
34156fc092 2021-01-20 18:52:11 +08:00
Redkale
86fde56129 Convert增加convertMapToBytes方法 2021-01-20 18:15:25 +08:00
Redkale
d997d3a7bb 增加ConvertSmallString功能 2021-01-20 17:37:29 +08:00
Redkale
4e689855f4 2021-01-20 13:20:03 +08:00
Redkale
eace16d7fd 2021-01-20 13:11:20 +08:00
Redkale
53b7f9b26f 2021-01-20 11:45:56 +08:00
Redkale
983c667725 2021-01-20 11:35:51 +08:00
Redkale
96fd660d46 2021-01-20 10:14:52 +08:00
Redkale
7d1770da8a 2021-01-19 17:40:08 +08:00
Redkale
b83f6867f3 2021-01-19 17:00:28 +08:00
Redkale
fa7db42f50 ObjectPool关闭public构造函数 2021-01-19 16:45:00 +08:00
Redkale
80c07a5c5b 2021-01-19 15:44:31 +08:00
Redkale
59a4c85aeb 2021-01-19 15:39:53 +08:00
Redkale
7fc01d38e8 2021-01-18 17:29:26 +08:00
Redkale
3010422f4e 2021-01-16 19:27:52 +08:00
Redkale
1f78bb1a98 2021-01-16 19:25:18 +08:00
Redkale
1d7f32efe4 2021-01-16 18:26:08 +08:00
Redkale
1e3d980437 2021-01-15 15:07:30 +08:00
Redkale
8654b5eef8 2021-01-14 13:37:45 +08:00
Redkale
5781ad1de0 2021-01-14 12:25:23 +08:00
Redkale
e2a1fa15d3 增加CacheClusterAgent功能 2021-01-14 12:01:25 +08:00
Redkale
50da7413d8 2021-01-13 09:24:35 +08:00
Redkale
e45b945024 2021-01-13 09:22:55 +08:00
Redkale
f3668a77ef 2021-01-12 21:39:56 +08:00
Redkale
2aee6cab20 2021-01-12 20:54:23 +08:00
Redkale
6233a0b960 2021-01-12 20:34:39 +08:00
Redkale
0ae469d8e2 2021-01-12 18:38:10 +08:00
Redkale
bcad47ebd5 修复HttpSimpleRequest的path编码bug 2021-01-12 17:59:33 +08:00
Redkale
71d179b8c3 2021-01-12 17:53:13 +08:00
Redkale
af35e5100e 2021-01-12 10:23:28 +08:00
Redkale
96c97c7dd2 2021-01-12 09:53:33 +08:00
Redkale
d5a41fc8b6 2021-01-10 14:59:00 +08:00
Redkale
c3c3afb3c3 2021-01-10 13:10:09 +08:00
Redkale
4f32dcda16 2021-01-10 10:33:48 +08:00
Redkale
67717e73ad 2021-01-10 10:19:05 +08:00
Redkale
1753734581 2021-01-10 09:05:47 +08:00
Redkale
3e408e535c 2021-01-09 15:41:35 +08:00
Redkale
f154292cb5 2021-01-09 15:32:59 +08:00
Redkale
ac261533c3 2021-01-09 14:53:12 +08:00
Redkale
1982c984ee 2021-01-09 14:42:45 +08:00
Redkale
fb5f82c44f 2021-01-09 14:01:41 +08:00
Redkale
840cea06db 2021-01-06 15:07:31 +08:00
Redkale
3237e2488e 2021-01-03 14:02:26 +08:00
Redkale
98e1e40e18 2021-01-03 14:00:54 +08:00
Redkale
def3fc7b2e 2021-01-03 12:04:51 +08:00
Redkale
6057b8f90a 2020-12-26 00:48:05 +08:00
Redkale
2847f761bb 修改MessageRecord的seqid生成规则 2020-12-26 00:07:49 +08:00
Redkale
b0a2d2ad80 2020-12-25 22:37:48 +08:00
Redkale
564b814f77 2020-12-25 20:51:18 +08:00
Redkale
433585a231 2020-12-25 20:33:50 +08:00
Redkale
6a4750e302 2020-12-25 20:30:47 +08:00
Redkale
748a6f11c1 2020-12-25 20:05:10 +08:00
Redkale
bdd9a82682 mq加入一些debug日志 2020-12-25 18:03:19 +08:00
Redkale
c551c157d1 @Local @AutoLoad(false) Service 能自动加载 2020-12-19 19:39:51 +08:00
Redkale
7e777229ba 2020-12-15 21:55:32 +08:00
Redkale
612bfcba37 WebSocket兼容connection:upgrade 小写的upgrade 2020-12-15 17:04:33 +08:00
Redkale
c44e00a100 2020-12-14 13:57:57 +08:00
Redkale
7f46b3194a Application 删除 restoreConfig 方法 2020-12-14 13:56:20 +08:00
Redkale
50b7999dee Application 增加 reloadConfig 方法 2020-12-14 13:55:19 +08:00
Redkale
871f84b1ff Redkale 2.3.0 开始 2020-12-14 13:49:47 +08:00
Redkale
4018a95af0 2020-12-13 12:17:00 +08:00
Redkale
ffe3ff5830 2020-12-13 01:08:09 +08:00
Redkale
9b9b0ab10e Redkale 2.2.0 结束 2020-12-12 09:36:29 +08:00
Redkale
b19e5fe839 2020-12-09 21:58:04 +08:00
Redkale
f6caf41960 2020-11-27 09:36:46 +08:00
Redkale
67d57de166 2020-11-12 21:59:16 +08:00
Redkale
4d79f17a3a 2020-11-12 21:38:21 +08:00
Redkale
245d6d6fc7 2020-11-12 09:08:15 +08:00
Redkale
66bd1feadf 2020-11-11 23:48:38 +08:00
Redkale
c02e3549eb 2020-11-11 23:28:58 +08:00
Redkale
210b8dcf9d 2020-11-11 22:55:58 +08:00
Redkale
bbefa788fd 2020-11-11 22:51:24 +08:00
Redkale
2f6eb0908e 2020-11-11 18:00:37 +08:00
Redkale
51e4d44fc1 2020-11-11 12:39:05 +08:00
Redkale
ed502daeb9 2020-11-10 21:11:11 +08:00
Redkale
d7da527bd5 2020-11-10 21:06:08 +08:00
Redkale
7c5146bc97 2020-11-10 00:22:03 +08:00
Redkale
91cdf9990b 2020-10-23 15:03:43 +08:00
Redkale
7d03609462 2020-10-10 12:00:13 +08:00
Redkale
7be9a06e76 2020-10-02 15:41:03 +08:00
Redkale
3eaecacac0 2020-10-02 00:19:04 +08:00
Redkale
9c5e23090c 2020-10-01 22:49:51 +08:00
Redkale
c7b05e530d 2020-10-01 15:38:39 +08:00
Redkale
889fa25e58 2020-10-01 00:38:41 +08:00
Redkale
da6945224f 2020-09-29 09:17:18 +08:00
Redkale
026a727480 2020-09-28 19:26:02 +08:00
Redkale
2404f547ab 2020-09-28 14:15:07 +08:00
Redkale
a9dd82dcf4 2020-09-27 18:59:54 +08:00
Redkale
95443be313 2020-09-27 11:25:57 +08:00
Redkale
5d1805b10e 2020-09-26 22:03:26 +08:00
Redkale
72eb175dc3 2020-09-25 22:03:19 +08:00
Redkale
d5cbcaaa15 2020-09-25 18:41:49 +08:00
Redkale
bfa722f6da 2020-09-25 16:56:10 +08:00
Redkale
6b9d35983a 2020-09-25 11:47:24 +08:00
Redkale
6cf50c7cc9 2020-09-24 23:32:26 +08:00
Redkale
cf05851752 2020-09-24 15:24:49 +08:00
Redkale
1cbbf17392 2020-09-24 14:50:05 +08:00
Redkale
96afeb19b2 2020-09-24 14:23:45 +08:00
Redkale
56da72b16e 2020-09-22 12:18:23 +08:00
Redkale
b781868876 2020-09-20 21:56:35 +08:00
Redkale
6a05f4b497 2020-09-20 17:43:46 +08:00
Redkale
b9fa617374 2020-09-20 17:00:03 +08:00
Redkale
c59baee1f5 2020-09-20 16:41:39 +08:00
Redkale
98531d6b2f 2020-09-20 16:21:47 +08:00
Redkale
8df5b45525 2020-09-20 15:22:38 +08:00
Redkale
ebba966d52 2020-09-20 15:15:34 +08:00
Redkale
169f35d41f 2020-09-20 12:08:49 +08:00
Redkale
8bec9e88a7 2020-09-20 12:08:20 +08:00
Redkale
854aa0153f 2020-09-19 23:29:10 +08:00
Redkale
77eaaae6ce 2020-09-19 23:17:12 +08:00
Redkale
fd7badec0a 2020-09-19 20:47:20 +08:00
Redkale
a834b6ea21 2020-09-19 20:23:51 +08:00
Redkale
31fad72172 CacheSource 增加 setBytes 系列方法 2020-09-19 09:53:58 +08:00
Redkale
ef14195e71 2020-09-18 22:58:10 +08:00
Redkale
a2fab32356 2020-09-18 22:32:25 +08:00
Redkale
2dd0ecfa49 2020-09-18 21:01:31 +08:00
Redkale
849fe15728 移除RestDyncListener 2020-09-18 21:00:31 +08:00
Redkale
76afab3c78 2020-09-18 14:09:27 +08:00
Redkale
21250794f5 2020-09-18 13:47:28 +08:00
Redkale
9f85ceb2ed 2020-09-17 19:08:54 +08:00
Redkale
b6ecdef0c5 2020-09-17 17:54:59 +08:00
Redkale
4dfd528533 2020-09-17 16:01:48 +08:00
Redkale
3131601477 2020-09-17 15:41:14 +08:00
Redkale
5921cf5f0d 增加RestDyncListener功能 2020-09-17 15:33:39 +08:00
Redkale
788f7d5eb1 2020-09-17 00:32:15 +08:00
Redkale
79cb79481e 2020-09-16 23:05:32 +08:00
Redkale
41f0061dca 2020-09-16 21:50:50 +08:00
Redkale
f981e4f886 2020-09-16 21:11:37 +08:00
Redkale
ebf30e488a 2020-09-15 23:41:17 +08:00
Redkale
7ab889baac 2020-09-15 21:37:58 +08:00
Redkale
8d9d893839 2020-09-14 11:16:16 +08:00
Redkale
205233f8c9 Utility增加todayYYYYMMDDHHmmss方法 2020-09-10 10:18:45 +08:00
Redkale
6ee9527ed9 HttpServlet 不再支持/aa/bbcc 能匹配到 /aa/bb 2020-09-09 19:17:04 +08:00
Redkale
ee56ffa346 2020-09-09 10:16:19 +08:00
Redkale
3fcc478356 修复创建HttpSimpleRequest时body参数没有解析的bug 2020-09-08 11:14:25 +08:00
Redkale
26e4cd2f4a 2020-09-08 09:54:21 +08:00
Redkale
509524144d 增加 ConvertLoader 2020-09-08 09:51:28 +08:00
Redkale
676285e20b 2020-09-07 23:04:44 +08:00
Redkale
43edb0f814 2020-09-03 15:01:06 +08:00
Redkale
1c684a4e32 2020-09-03 14:59:35 +08:00
Redkale
156af0e2a4 2020-09-03 11:45:02 +08:00
Redkale
28d9c465fd 2020-09-03 09:22:55 +08:00
Redkale
a285510656 2020-09-02 20:41:19 +08:00
Redkale
d6042d142e [优化]增加org.redkale.service.RetLabel.RetInfoTransfer 2020-08-31 21:07:50 +08:00
Redkale
be8d368e72 2.2.0 开始 2020-08-31 21:06:54 +08:00
Redkale
75698d9390 2020-08-31 13:35:52 +08:00
Redkale
9d343694cc <tt>替换成<code> 2020-08-31 09:31:38 +08:00
Redkale
fddb2a3be0 2020-08-28 22:35:43 +08:00
Redkale
3b44eddbb9 2020-08-28 19:37:34 +08:00
Redkale
ba4100e22d 增加 ThreadHashExecutor 2020-08-28 15:15:26 +08:00
Redkale
72155e31dd 2020-08-19 23:03:35 +08:00
Redkale
60903c844e 2020-08-19 22:56:26 +08:00
Redkale
5c810b5ff6 2020-08-11 19:57:17 +08:00
Redkale
e3a8c2d392 2020-08-06 16:33:49 +08:00
Redkale
1f27d5f3e3 完善Rest的泛型识别 2020-08-06 16:06:46 +08:00
Redkale
abb790da54 2020-07-31 12:00:27 +08:00
Redkale
f4a2f2af94 2020-07-31 10:26:26 +08:00
Redkale
29a21d060b 2020-07-31 10:22:19 +08:00
Redkale
de19861974 2020-07-31 10:13:53 +08:00
Redkale
e5766e31dc 2020-07-31 09:50:59 +08:00
Redkale
fca727ecaf 2020-07-30 20:54:35 +08:00
Redkale
d009c9b2ed 2020-07-30 19:14:39 +08:00
Redkale
fd2e84f781 2020-07-30 18:02:29 +08:00
Redkale
2b7676449d 2020-07-30 17:57:31 +08:00
Redkale
4b2c6eba63 2020-07-30 17:35:59 +08:00
Redkale
84147280cf 2020-07-30 09:44:07 +08:00
Redkale
e62d9f8201 2020-07-30 09:11:49 +08:00
Redkale
4cec4e64f9 2020-07-30 09:10:08 +08:00
Redkale
9eb647428c 2020-07-29 21:20:12 +08:00
Redkale
b68808b325 加入spop系列方法 2020-07-29 20:08:47 +08:00
Redkale
a9dce0efbf 2020-07-27 16:43:56 +08:00
Redkale
de63f81238 CacheSource remove系列方法返回值由void改成int 2020-07-25 09:39:43 +08:00
Redkale
a05afe45c0 2020-07-24 09:41:43 +08:00
Redkale
236996caa1 2020-07-22 13:41:54 +08:00
Redkale
b808c93885 2020-07-22 11:53:16 +08:00
Redkale
7865b74359 2020-07-22 11:27:10 +08:00
Redkale
143e1880d4 2020-07-22 11:24:39 +08:00
Redkale
1be467cfe9 2020-07-22 11:09:49 +08:00
Redkale
7f8f157616 2020-07-21 19:49:32 +08:00
Redkale
c140ad6828 2020-07-20 11:45:51 +08:00
Redkale
50e41dba25 2020-07-19 21:36:19 +08:00
Redkale
c73fc5f266 2020-07-19 15:25:59 +08:00
Redkale
a5f3adc477 2020-07-19 13:42:26 +08:00
Redkale
b77764c1cf 2020-07-17 20:18:10 +08:00
Redkale
714b188560 2020-07-17 18:21:09 +08:00
Redkale
47315f188a 2020-07-17 17:37:02 +08:00
Redkale
384a8a3991 2020-07-17 16:57:41 +08:00
Redkale
7a80c00439 2020-07-17 12:13:45 +08:00
Redkale
43486ce1e2 2020-07-17 11:43:51 +08:00
Redkale
627c1e953e CacheSource增加hxxx方法 2020-07-17 10:41:41 +08:00
Redkale
da141cc6bd 2020-07-16 23:43:35 +08:00
Redkale
8f3a9a6297 2020-07-16 17:50:04 +08:00
Redkale
e8d496b0ad 2020-07-16 17:30:27 +08:00
Redkale
f5accfbe8f 2020-07-15 23:07:55 +08:00
Redkale
16e291036e 2020-07-15 21:02:00 +08:00
Redkale
a79b8b77b5 2020-07-15 20:58:03 +08:00
Redkale
8e2d6acdf8 2020-07-15 19:34:31 +08:00
Redkale
70c5123f7a 增加强大的HttpMessageClusterClient功能 2020-07-15 18:03:33 +08:00
Redkale
7cfbaee199 2020-07-14 23:23:34 +08:00
Redkale
fa8d78e18f 2020-07-13 22:57:21 +08:00
Redkale
4f5e72a31a 2020-07-13 22:56:42 +08:00
Redkale
7c5822fb7c 2020-07-12 17:56:58 +08:00
Redkale
60df140bfd 2020-07-11 20:22:44 +08:00
Redkale
f41e905842 RetResult增加CompletableFuture相关方法 2020-07-11 11:02:18 +08:00
Redkale
9824fe6da3 2020-07-11 10:45:12 +08:00
Redkale
1fb37f4b67 2020-07-10 17:50:48 +08:00
Redkale
a8a6861a21 2020-07-09 19:50:06 +08:00
Redkale
614222bdc3 2020-07-09 16:58:05 +08:00
Redkale
8e98dda795 2020-07-09 00:22:19 +08:00
Redkale
3686306505 2020-07-08 23:18:28 +08:00
Redkale
d29aa78022 2020-07-04 23:52:27 +08:00
Redkale
85fa406e1d 2020-07-03 09:21:49 +08:00
Redkale
d501e2016f 2020-07-01 18:08:39 +08:00
Redkale
cf0cd66ac9 2020-07-01 15:02:26 +08:00
Redkale
c921f657b1 2020-06-30 20:33:07 +08:00
Redkale
c93c1d84c5 2020-06-30 19:30:53 +08:00
Redkale
2e66b1a546 2020-06-29 20:12:37 +08:00
Redkale
48629146ed 2020-06-28 23:18:59 +08:00
Redkale
a6c8502416 2020-06-28 23:16:53 +08:00
Redkale
fc74dc33c1 2020-06-28 22:49:14 +08:00
Redkale
73de9dfc33 2020-06-28 22:22:53 +08:00
Redkale
68d78a4aa4 2020-06-28 19:28:56 +08:00
Redkale
b618e0e884 2020-06-28 09:45:53 +08:00
Redkale
2d1a6e0edc 2020-06-28 07:23:07 +08:00
Redkale
76a7e92787 2020-06-26 22:06:22 +08:00
Redkale
a2178b9a5f 2020-06-26 00:45:29 +08:00
Redkale
dcf0fecdb0 2020-06-26 00:38:24 +08:00
Redkale
f88db8abf9 2020-06-25 23:33:57 +08:00
Redkale
0c8b0f5e19 2020-06-25 20:55:17 +08:00
Redkale
b794872147 2020-06-25 17:34:04 +08:00
Redkale
86614f035b 2020-06-25 16:14:57 +08:00
Redkale
5f3a472c5e 2020-06-24 23:08:17 +08:00
Redkale
7eb2a405d3 2020-06-24 18:04:42 +08:00
Redkale
1d030183bb 2020-06-24 16:34:58 +08:00
Redkale
d211692306 2020-06-24 10:43:46 +08:00
Redkale
86c7d95c80 2020-06-24 10:05:02 +08:00
Redkale
e99d43b25c 2020-06-24 09:25:23 +08:00
Redkale
730fc0a911 2020-06-23 10:28:25 +08:00
Redkale
1ea92d7165 2020-06-23 10:13:12 +08:00
Redkale
0dfc0ca853 2020-06-22 11:07:26 +08:00
Redkale
474f82b3cf 2020-06-21 09:41:14 +08:00
Redkale
ae80109c77 2020-06-21 09:15:17 +08:00
Redkale
807fe63cbe HttpSimpleRequest 增加 rpc 功能 2020-06-21 08:57:59 +08:00
Redkale
44ed3259f9 2020-06-19 13:56:46 +08:00
Redkale
93b2b5fab8 2020-06-19 00:46:05 +08:00
Redkale
58e807439c 2020-06-19 00:20:57 +08:00
Redkale
ca2f34bfac 2020-06-19 00:18:38 +08:00
Redkale
b8719d7f76 去掉Service.stop 增加 @Command 功能 2020-06-18 15:35:40 +08:00
Redkale
be0fdd9045 2020-06-18 15:00:14 +08:00
Redkale
1d2b583c0c 2020-06-17 22:50:04 +08:00
Redkale
9def35e2e1 2020-06-17 22:49:27 +08:00
Redkale
a11127ea58 2020-06-17 13:39:08 +08:00
Redkale
af80864e08 2020-06-16 21:03:22 +08:00
Redkale
f6a4fbdf87 2020-06-16 20:57:09 +08:00
Redkale
61f48be2a6 2020-06-16 19:58:08 +08:00
Redkale
8516925537 Service 增加 stop 方法 2020-06-16 17:48:19 +08:00
Redkale
f828ec3d08 2020-06-16 15:33:49 +08:00
Redkale
1eb1706166 2020-06-16 11:12:51 +08:00
Redkale
ffd3b6daf6 2020-06-15 23:35:26 +08:00
Redkale
76d538264a 2020-06-15 23:16:17 +08:00
Redkale
02d0a06195 2020-06-15 20:57:59 +08:00
Redkale
c43325e402 2020-06-15 18:01:49 +08:00
Redkale
63bc4b2d00 CacheSource 增加get多个keys值得系列方法 2020-06-14 21:52:08 +08:00
Redkale
6e5da92263 2020-06-14 14:25:13 +08:00
Redkale
6358719255 2020-06-14 12:04:59 +08:00
Redkale
bdfd92299a 2020-06-14 12:00:03 +08:00
Redkale
aa4c9896ba 2020-06-14 01:21:26 +08:00
Redkale
1549f1feed 2020-06-14 01:13:08 +08:00
Redkale
2a9a713f3e 2020-06-14 01:12:26 +08:00
Redkale
0377dac71f 2020-06-14 01:01:38 +08:00
Redkale
13217a11c0 2020-06-13 09:38:25 +08:00
Redkale
146b81ee5e 2020-06-12 19:21:41 +08:00
Redkale
8502792aad 2020-06-12 18:10:00 +08:00
Redkale
3d9447327a 2020-06-12 17:20:36 +08:00
Redkale
288fc67621 2020-06-12 14:08:04 +08:00
Redkale
d4bc751a20 2020-06-12 09:35:41 +08:00
Redkale
4cf160e5d3 2020-06-11 23:30:43 +08:00
Redkale
98f29d6a6e 2020-06-11 19:24:16 +08:00
Redkale
92bb0a561b 2020-06-11 17:27:25 +08:00
Redkale
1329f6f0e1 2020-06-11 17:11:31 +08:00
Redkale
a3dbfaba88 2020-06-11 16:03:39 +08:00
Redkale
2032f39bf9 2020-06-11 14:51:22 +08:00
Redkale
8840415739 MessageAgent增加timeoutExecutor 2020-06-11 14:25:50 +08:00
Redkale
bdf2fd21c3 增加 @MessageMultiConsumer 功能 2020-06-11 14:06:25 +08:00
Redkale
bd1e326404 Rest配置中开启MQ时,path字段失效 2020-06-11 10:47:14 +08:00
Redkale
ebd31bc3d3 2020-06-11 10:16:48 +08:00
Redkale
7185191d91 2020-06-10 23:06:20 +08:00
Redkale
1a1dd44f34 2020-06-10 22:07:20 +08:00
Redkale
95fd147268 2020-06-10 20:37:24 +08:00
Redkale
88657fdf63 2020-06-10 20:30:50 +08:00
Redkale
03de684940 2020-06-10 17:25:52 +08:00
Redkale
b445b99572 2020-06-10 10:34:38 +08:00
Redkale
bd4343c5d8 2020-06-09 21:31:08 +08:00
Redkale
a58c13cd9f 2020-06-09 21:22:17 +08:00
Redkale
cf23ecc12c 2020-06-09 17:46:50 +08:00
Redkale
86754c2324 2020-06-09 13:10:16 +08:00
Redkale
e6f0a8fdf3 增加 @RestHeaders 功能 2020-06-09 09:53:32 +08:00
Redkale
fa9fc531d0 2020-06-08 22:51:14 +08:00
Redkale
30bf2c1ad3 2020-06-08 22:43:46 +08:00
Redkale
d326da9344 2020-06-08 22:27:30 +08:00
Redkale
8f6494163d 2020-06-08 21:57:55 +08:00
Redkale
490cabefb2 增加 <excludelibs/> 配置项 2020-06-08 21:45:19 +08:00
Redkale
66ff86d6fb 2020-06-08 20:13:26 +08:00
Redkale
0e5479d55e 增加 @RpcTargetTopic 2020-06-08 19:31:29 +08:00
Redkale
3eb3e0104d 2020-06-08 13:42:19 +08:00
Redkale
079e6116b2 2020-06-08 09:13:41 +08:00
Redkale
b6a3adb21c 2020-06-07 22:11:49 +08:00
Redkale
ecf831c0f5 2020-06-07 15:56:55 +08:00
Redkale
adfa0be79e 2020-06-07 11:27:40 +08:00
Redkale
7ec91802b2 2020-06-06 23:51:56 +08:00
Redkale
1e15eb31c7 2020-06-06 23:37:59 +08:00
Redkale
8d5e61a9a2 2020-06-06 22:04:18 +08:00
Redkale
64500b113a 2020-06-06 18:50:18 +08:00
Redkale
a7e5fad571 2020-06-05 18:44:51 +08:00
Redkale
531b00b6fd 2020-06-05 18:01:25 +08:00
Redkale
ce3fc5792b 2020-06-05 17:52:09 +08:00
Redkale
a477b2fb73 2020-06-05 13:50:58 +08:00
Redkale
6a5d121615 2020-06-05 12:01:32 +08:00
Redkale
90960e0574 2020-06-05 11:56:04 +08:00
Redkale
b6980f7cf8 2020-06-05 11:29:54 +08:00
Redkale
2fb3472de0 2020-06-05 10:06:44 +08:00
Redkale
6dacbafc29 2020-06-05 07:50:10 +08:00
Redkale
f1fcbd7396 2020-06-04 22:22:35 +08:00
Redkale
681e389f19 2020-06-04 21:32:18 +08:00
Redkale
06b7274364 2020-06-04 20:56:45 +08:00
Redkale
b4f7de4858 2020-06-04 20:14:16 +08:00
Redkale
6261232ce6 2020-06-04 19:53:41 +08:00
Redkale
eb35b90950 2020-06-04 18:03:02 +08:00
Redkale
958cea4e0d 2020-06-04 17:56:13 +08:00
Redkale
7f184bae50 2020-06-04 17:25:42 +08:00
Redkale
3d68103a19 2020-06-04 17:09:30 +08:00
Redkale
612851bce0 2020-06-04 16:21:28 +08:00
Redkale
e365dae9e4 2020-06-04 14:06:35 +08:00
Redkale
b6d5fc02dc 2020-06-04 10:11:14 +08:00
Redkale
59d139ace2 2020-06-04 09:44:00 +08:00
Redkale
1d7a72f992 2020-06-04 09:39:38 +08:00
Redkale
45f2ce261e 2020-06-04 09:29:04 +08:00
Redkale
f79e49db5a 2020-06-03 23:21:57 +08:00
Redkale
218aebaa0f 2020-06-03 22:34:10 +08:00
Redkale
f11870d6bc 2020-06-03 20:06:48 +08:00
Redkale
ebea6bb92c 2020-06-03 19:58:13 +08:00
Redkale
4806d6ada0 2020-06-03 19:46:25 +08:00
Redkale
6909748bda 2020-06-03 19:26:38 +08:00
Redkale
982fc8440c 2020-06-03 17:53:55 +08:00
Redkale
e4df07a00c 2020-06-03 17:02:23 +08:00
Redkale
0ee30aca7e 2020-06-03 16:45:28 +08:00
Redkale
b994bcbcfb 2020-06-03 16:23:16 +08:00
Redkale
cc23b44409 2020-06-03 15:48:40 +08:00
Redkale
de36ef697d 2020-06-03 15:23:45 +08:00
Redkale
e0d224a330 2020-06-03 14:58:44 +08:00
Redkale
adc2106bec 2020-06-03 14:15:42 +08:00
Redkale
6cdbe957a7 2020-06-03 14:03:46 +08:00
Redkale
14808cb01c 2020-06-03 13:55:08 +08:00
Redkale
1edadbfee8 2020-06-03 12:03:04 +08:00
Redkale
043a23ecdf 2020-06-03 09:29:54 +08:00
Redkale
383ef37989 2020-06-02 23:18:36 +08:00
Redkale
9cd9a8d3ea 2020-06-02 09:56:01 +08:00
Redkale
db8c94f433 2020-06-01 21:19:47 +08:00
Redkale
22fb3e5bef 2020-06-01 13:44:34 +08:00
Redkale
6329722f17 2020-06-01 11:04:03 +08:00
Redkale
2dee61223d 2020-06-01 10:04:20 +08:00
Redkale
f83fc52e9c 2020-05-31 11:59:11 +08:00
Redkale
2f8a04c15d 2020-05-31 08:42:51 +08:00
Redkale
a1501af7a7 2020-05-30 19:55:07 +08:00
Redkale
a1fdfc9cc9 2020-05-30 17:59:28 +08:00
Redkale
2dddf3c2a5 2020-05-30 17:53:59 +08:00
Redkale
84061cf60f 2020-05-30 17:42:28 +08:00
Redkale
557c2c7858 2020-05-30 16:40:33 +08:00
Redkale
cb2d355bc9 2020-05-30 15:57:56 +08:00
Redkale
ed1b642d5b 2020-05-30 14:50:07 +08:00
Redkale
411f5e1951 2020-05-30 11:55:34 +08:00
Redkale
450506ca96 2020-05-30 11:32:16 +08:00
Redkale
bf700aa88f 2020-05-30 10:23:36 +08:00
Redkale
c108ab196c 2020-05-30 10:18:00 +08:00
Redkale
cac8662c01 2020-05-30 09:31:38 +08:00
Redkale
197c58ef98 2020-05-30 09:24:40 +08:00
Redkale
d4c2723759 删除MessageStreams 2020-05-29 23:18:59 +08:00
Redkale
c34a6d8f49 2020-05-29 22:34:53 +08:00
Redkale
5de580c00b 2020-05-29 21:04:00 +08:00
Redkale
ed1fb151d7 2020-05-29 16:06:02 +08:00
Redkale
4c4913c5d0 2020-05-29 13:43:47 +08:00
Redkale
adb0dc5963 2020-05-29 11:15:56 +08:00
Redkale
740bc8ae31 增加@RestUserid 废弃 HttpRequest.currentUser() 方法, 建议 HttpRequest.currentUserid() 2020-05-28 20:20:08 +08:00
Redkale
30a0b12020 2020-05-28 19:11:28 +08:00
Redkale
b0b8b0db3b 2020-05-28 11:40:03 +08:00
Redkale
71244732f2 2020-05-28 11:22:30 +08:00
Redkale
820af60c19 2020-05-28 10:03:13 +08:00
Redkale
b3252359bd 2020-05-28 09:55:05 +08:00
Redkale
9ade568597 2020-05-28 09:51:57 +08:00
Redkale
cf5224a5f6 2020-05-28 09:38:18 +08:00
Redkale
6c4a83d14d 2020-05-27 20:32:57 +08:00
Redkale
0439b95139 2020-05-27 19:18:48 +08:00
Redkale
72a618a0b7 2020-05-27 18:02:51 +08:00
Redkale
0f7520e67b 2020-05-27 17:10:23 +08:00
Redkale
fcd69474a2 2020-05-27 15:22:41 +08:00
Redkale
3130e00bab 2020-05-27 15:08:12 +08:00
Redkale
1c063b57ec 2020-05-27 15:01:36 +08:00
Redkale
efeff3b720 2020-05-27 14:21:01 +08:00
Redkale
ea15634f47 2020-05-27 12:00:32 +08:00
Redkale
e744d001c6 2020-05-27 11:49:44 +08:00
Redkale
06e486e5e2 2020-05-27 11:32:29 +08:00
Redkale
95180ffdef 2020-05-27 11:31:29 +08:00
Redkale
e5bd85e9aa 2020-05-27 11:23:07 +08:00
Redkale
ec4ec2ff77 2020-05-26 22:22:44 +08:00
Redkale
5a1c9215bc 2020-05-26 19:11:12 +08:00
Redkale
53457b73ad 加入MQ功能 2020-05-26 17:59:00 +08:00
Redkale
8cb9fcf01a 2020-05-22 19:45:57 +08:00
Redkale
2c88b0e75e 2020-05-22 16:49:45 +08:00
Redkale
4daffdc31f 2020-05-21 20:23:56 +08:00
Redkale
16dec2cde5 2020-05-17 23:37:22 +08:00
Redkale
82e5fb593e 2020-05-17 22:25:47 +08:00
Redkale
4a60ecb3ff 2020-05-17 22:11:34 +08:00
Redkale
38307405ed 2020-05-17 20:34:36 +08:00
Redkale
fe332d0cbd 2020-05-17 19:08:43 +08:00
Redkale
e45f75c1d6 2020-05-17 16:39:51 +08:00
Redkale
a77f450757 2020-05-17 15:49:32 +08:00
Redkale
9f8e946ea3 2020-05-16 22:40:41 +08:00
Redkale
7633687665 2020-05-16 22:24:37 +08:00
Redkale
a1e37643d0 2020-05-16 22:12:45 +08:00
Redkale
8440b58d6c 2020-05-16 20:34:03 +08:00
Redkale
a97f8efe21 2020-05-16 20:10:21 +08:00
Redkale
d83e7c22ac 2020-05-16 19:59:49 +08:00
Redkale
01a5b32b22 ClusterAgent 2020-05-16 17:51:30 +08:00
Redkale
8834f57582 2020-05-16 17:22:52 +08:00
Redkale
57fd7b96b4 $cluster 2020-05-16 17:03:55 +08:00
Redkale
14fe2fbc84 2020-05-16 14:46:11 +08:00
Redkale
0b86edb654 2020-05-16 14:27:46 +08:00
Redkale
07ab74902c 2020-05-16 14:27:08 +08:00
Redkale
e4c6e860c1 DataCallAttribute移至RpcCallAttribute 2020-05-16 09:12:06 +08:00
Redkale
02cf587fcf 2020-05-16 09:09:43 +08:00
Redkale
081773163b 2020-05-16 09:03:18 +08:00
Redkale
292ff63699 移除RpcMultiRun功能 2020-05-15 22:02:54 +08:00
Redkale
f1a97c0219 移除DataCacheListener功能 2020-05-15 21:53:21 +08:00
Redkale
e545010034 2020-05-15 17:36:19 +08:00
Redkale
ef57fa9a25 2020-05-15 15:01:18 +08:00
Redkale
1bd0d891a4 2020-05-15 14:39:29 +08:00
Redkale
9a51c1de1d Application加入nodeid属性 2020-05-15 14:38:53 +08:00
Redkale
e4bb75dd8e 2020-05-15 14:09:49 +08:00
Redkale
66e1e08ae2 2020-05-05 19:54:13 +08:00
Redkale
708cd5a644 修复DeMember/EnMember中attribute.type值不能精准显示泛型的bug 2020-05-04 22:12:25 +08:00
Redkale
138c9aba97 2020-05-04 20:59:28 +08:00
Redkale
e5e17b4496 2020-05-04 20:52:00 +08:00
Redkale
cadaebefb9 2020-05-04 20:21:49 +08:00
Redkale
e2fb7935f6 2020-05-04 20:02:18 +08:00
Redkale
16b3dab600 2020-05-04 19:51:19 +08:00
Redkale
758972890e 2020-04-17 11:08:30 +08:00
Redkale
a88285d935 回滚Mask convertFrom 方法 2020-04-16 22:08:14 +08:00
Redkale
d7832fb931 Convert增加convertFrom(final Type type, final ConvertMask mask, final byte[] bytes) 方法 2020-04-16 21:42:52 +08:00
Redkale
f073c9a0bc 2020-04-16 21:08:00 +08:00
Redkale
63ef83ec62 WebSocket支持permessage-deflate单向功能 2020-04-16 20:19:49 +08:00
Redkale
51c50415e1 Redkale 2.0.0 正式版 结束 2020-04-08 13:24:51 +08:00
Redkale
2f08fa6476 2020-04-03 15:10:57 +08:00
Redkale
3091972fc5 2020-04-02 17:28:58 +08:00
Redkale
8e14df9a95 2020-04-01 13:33:43 +08:00
Redkale
683cec6f4d 2020-04-01 13:33:04 +08:00
Redkale
ec6e5aa3b1 2020-02-24 07:49:34 +08:00
Redkale
f4c00a9b6f 2020-02-12 11:43:13 +08:00
Redkale
c071ec5d6c 2020-02-09 12:37:40 +08:00
Redkale
29148c4b42 TypeToken.getGenericType加强 2020-02-09 12:37:00 +08:00
Redkale
7340caa4a9 2020-02-09 11:35:07 +08:00
Redkale
7d23dfa73d 2020-02-09 11:34:04 +08:00
Redkale
19932820a9 2020-02-06 16:28:48 +08:00
Redkale
6b59c54087 Redkale 2.0.0.rc4 结束 2020-02-02 10:48:54 +08:00
Redkale
58f5ee999a 2020-01-30 12:04:56 +08:00
Redkale
32e8c033ea 2020-01-30 12:02:42 +08:00
Redkale
84a96f750f 2020-01-30 11:53:17 +08:00
Redkale
6560e71e48 2020-01-30 11:44:46 +08:00
Redkale
ee8a18a528 2020-01-30 11:35:05 +08:00
Redkale
c36fc36964 2020-01-29 12:31:11 +08:00
Redkale
a34f85bfc9 2020-01-29 11:35:49 +08:00
Redkale
6f00efa077 2020-01-29 11:28:24 +08:00
Redkale
469dff8478 2020-01-27 18:39:11 +08:00
Redkale
c50eb79b1d 2020-01-27 15:57:13 +08:00
Redkale
985bf6ed25 2020-01-27 15:56:41 +08:00
Redkale
bd51696e08 2020-01-27 14:03:53 +08:00
Redkale
2764d59a4f 2020-01-27 13:01:43 +08:00
Redkale
c1509bb712 2020-01-27 12:32:22 +08:00
Redkale
b14f32deb3 2020-01-27 12:31:34 +08:00
Redkale
62145a2aad 2020-01-27 12:23:33 +08:00
Redkale
8fb88a57b2 2020-01-26 20:20:17 +08:00
Redkale
44f12ae003 2020-01-26 15:51:05 +08:00
Redkale
bf97ef3a08 2020-01-26 14:03:49 +08:00
Redkale
aeefc3b8a2 2020-01-17 14:43:33 +08:00
Redkale
5763718816 WebSocketRunner加入写队列 2020-01-17 14:39:19 +08:00
Redkale
3b142b7504 PoolSource的默认超时时间从3秒改成6秒 2020-01-17 14:04:15 +08:00
Redkale
0f52d32424 TcpAioAsyncConnection去掉队列写 2020-01-17 13:57:41 +08:00
Redkale
f5f3c48f38 2020-01-16 17:24:46 +08:00
Redkale
9f9f5aa000 HttpResponse增加retResultHandler属性 2020-01-16 16:59:37 +08:00
Redkale
be4ca0287b HttpResponse增加retResultHandler属性 2020-01-16 11:11:34 +08:00
Redkale
a84ed72f28 2020-01-14 16:16:28 +08:00
Redkale
8eb5f56f42 2020-01-14 10:59:45 +08:00
Redkale
df1aa2b379 2020-01-11 22:02:42 +08:00
Redkale
da2befcb97 2020-01-11 21:22:34 +08:00
Redkale
92d0f7e796 2020-01-11 21:17:11 +08:00
Redkale
6aa3949d05 DataSource增加可group by的queryColumnMap系列方法,缓存EntityCache部分未实现 2020-01-11 13:32:31 +08:00
Redkale
fa833d9224 2020-01-10 20:30:08 +08:00
Redkale
c9261f8475 增加ofArray方法 2020-01-10 19:25:17 +08:00
Redkale
a1df62af08 2020-01-10 19:20:32 +08:00
Redkale
aa12413f4e 2020-01-10 19:15:37 +08:00
Redkale
2ccd9ba10f ColumnExpress增加减法DEC 2020-01-10 19:10:10 +08:00
Redkale
81ae68c571 ColumnExpress增加减法DEC 2020-01-10 19:08:50 +08:00
Redkale
51b45f4713 DataSource.insert增加Collection、Stream方法 2020-01-08 13:36:59 +08:00
Redkale
66e1f58879 2020-01-08 10:42:08 +08:00
Redkale
06bb5180cf 【不兼容】WebSocket中onConnected、onClose方法的返回值由void改成CompletableFuture 2020-01-08 10:36:54 +08:00
Redkale
d83d7f879c 2020-01-07 16:32:03 +08:00
Redkale
b8e92c949e 2020-01-07 16:31:32 +08:00
Redkale
91548a0ca9 2020-01-07 16:31:02 +08:00
Redkale
dbca25cd54 2020-01-07 16:29:38 +08:00
Redkale
539ea15ae5 2020-01-07 16:28:11 +08:00
Redkale
ad1d9f33d4 WebSocket增加getUserSet方法 2020-01-07 13:07:04 +08:00
Redkale
df98c1a58e 优化querySet和queryColumnSet系列方法 2020-01-07 11:48:30 +08:00
Redkale
56d1969c96 2020-01-07 11:46:34 +08:00
Redkale
4b341436af 2020-01-07 11:01:08 +08:00
Redkale
4d3d73b4c1 WebSocketRange增加几个小方法 2020-01-07 10:21:01 +08:00
Redkale
55ab279e7f 2020-01-02 09:51:37 +08:00
Redkale
82ab994608 2019-12-19 10:55:11 +08:00
Redkale
1c4035e677 2019-12-18 23:50:29 +08:00
Redkale
afdc9e7207 2019-12-18 23:00:23 +08:00
Redkale
9b83abb06a Attribute增加subclass参数用于识别泛型的子类 2019-12-18 22:06:54 +08:00
Redkale
26d1a10bd0 2019-12-18 19:51:35 +08:00
Redkale
7e55dcc46d FilterNode兼容String的 >= > < <= 2019-12-11 19:01:45 +08:00
Redkale
45802d2403 修复2019.6.20改动时remoteAddrHeader带来的bug 2019-12-07 21:02:13 +08:00
Redkale
3660a2a4e5 2019-12-07 19:43:43 +08:00
Redkale
bed81bd93d 修复WriteMoreCompletionHandler的bug 2019-11-30 11:14:44 +08:00
Redkale
131855cdc5 2019-11-30 09:04:01 +08:00
Redkale
8b69e7d02b Redkale 2.0.0.rc3 结束 2019-11-25 16:33:48 +08:00
Redkale
02a10bf014 2019-11-23 10:55:29 +08:00
Redkale
004b83172e 2019-11-23 09:28:18 +08:00
Redkale
fee4555cef 2019-11-23 09:04:08 +08:00
Redkale
758bd7de72 2019-11-23 09:01:53 +08:00
Redkale
b2dd366640 2019-11-19 20:47:16 +08:00
Redkale
934c82eadd 优化JsonWrite.writeSmallString方法 2019-11-18 13:42:55 +08:00
Redkale
c7ed6574cc 优化JsonWrite.writeSmallString方法 2019-11-18 13:34:51 +08:00
Redkale
2ea2667fa7 Utility增加byteArray方法 2019-11-18 13:25:51 +08:00
Redkale
34ae2d38c5 2019-11-15 15:54:34 +08:00
Redkale
a1c95544cb 2019-11-15 15:19:16 +08:00
Redkale
c6dc38c35c PoolTcpSource增加ping接口 2019-11-14 12:04:22 +08:00
Redkale
39203ab598 2019-11-13 10:11:35 +08:00
Redkale
51a95a84aa 去掉AsyncConnection内的ByteBufferPool,HttpResponse合并header和body的Buffer 2019-11-13 10:07:48 +08:00
Redkale
8a8d45e642 DataSource增加判断字符串字段值长度的FilterExpress 2019-11-11 11:10:32 +08:00
Redkale
52eb7dbc0c 2019-11-07 09:55:16 +08:00
Redkale
0e14b60f12 2019-11-05 21:21:57 +08:00
Redkale
d373ab7204 2019-11-05 09:31:38 +08:00
Redkale
4f9a563ba7 2019-11-05 09:26:15 +08:00
Redkale
852da19b1e Redkale 2.0.0.rc2 结束 2019-11-05 09:21:49 +08:00
Redkale
ddfc040a53 2019-11-05 09:16:34 +08:00
Redkale
df3ccb763a 2019-11-04 11:53:11 +08:00
Redkale
f42561ca93 convert支持sql包的几个date类型 2019-11-03 11:47:54 +08:00
Redkale
580e28519a 2019-11-02 15:08:38 +08:00
Redkale
9ecc1d8f19 2019-11-02 14:20:07 +08:00
Redkale
40629ed7b9 2019-10-28 13:14:38 +08:00
Redkale
5790135add 2019-10-28 11:59:23 +08:00
Redkale
fd862ed6c6 Convert兼容java.util.Map.Entry 2019-10-28 11:56:45 +08:00
Redkale
33763af96c 兼容TypeToken.typeToClass 方法 2019-10-26 16:03:36 +08:00
Redkale
7c05df3cfb 2019-10-26 15:32:16 +08:00
Redkale
f471e2d4c5 配置支持远程地址 2019-10-26 09:45:33 +08:00
Redkale
d4fd093521 2019-10-25 11:42:50 +08:00
Redkale
40003c7789 2019-10-24 11:45:51 +08:00
Redkale
b94f99f338 2019-10-22 09:11:37 +08:00
Redkale
bd21644571 Redkale 2.0.0.rc1 结束 2019-10-18 08:42:28 +08:00
Redkale
5f3599d9b8 2019-10-17 18:51:08 +08:00
Redkale
1e4a30bd70 2019-10-16 15:17:04 +08:00
Redkale
e7dc5de9f2 2019-10-15 22:18:44 +08:00
Redkale
ccb9cb28f5 修复JsonByteBufferWriter的utf8问题 2019-10-15 21:55:31 +08:00
Redkale
4d9b72c922 2019-10-15 21:43:45 +08:00
Redkale
a51ae13a39 2019-10-15 18:02:34 +08:00
Redkale
dfca186688 2019-10-15 18:01:34 +08:00
Redkale
fadd229a89 2019-10-14 15:29:28 +08:00
Redkale
7acc69adc4 2019-10-14 12:32:53 +08:00
Redkale
d88e4120a1 2019-10-13 17:29:12 +08:00
Redkale
ef98edd91a Convert.newConvert 增加第2个Function参数 2019-10-13 12:55:00 +08:00
Redkale
f4548bbe34 2019-10-11 11:13:41 +08:00
Redkale
11a5faca1d Utility增加reverseSort方法 2019-10-11 08:59:40 +08:00
Redkale
c37b0e8cb5 Redkale 2.0.0.beta5 结束 2019-10-10 09:21:48 +08:00
Redkale
a20570a6eb 2019-10-10 09:17:42 +08:00
Redkale
5e3edb7e1d 2019-10-09 13:43:11 +08:00
Redkale
ad8f1d2da6 增加util.ResourceInjectLoader功能 2019-10-09 13:42:29 +08:00
Redkale
24b23c894f 修复FileSimpledCoder的instance写错的bug 2019-10-09 13:41:39 +08:00
Redkale
c551d5fb81 2019-09-26 16:32:36 +08:00
Redkale
fba43894c1 2019-09-26 16:27:42 +08:00
Redkale
22cc7e086c RetResult增加Convert属性 2019-09-26 16:22:56 +08:00
Redkale
1791008729 2019-09-25 15:41:19 +08:00
Redkale
90e15dd253 2019-09-25 15:40:47 +08:00
Redkale
7db73c076c 2019-09-25 15:33:18 +08:00
Redkale
95ad6e99d9 2019-09-23 18:57:45 +08:00
Redkale
0b2a5d0f61 2019-09-23 08:59:03 +08:00
Redkale
b7acce0814 Redkale 2.0.0.beta4 结束 2019-09-20 08:58:51 +08:00
Redkale
8744e76cad 2019-09-19 21:52:52 +08:00
Redkale
446b3c13dc 2019-09-19 21:38:53 +08:00
Redkale
3951e28148 2019-09-19 21:38:22 +08:00
Redkale
b74d679608 修复ByteBuffer Utility.encodeUTF8的bug 2019-09-19 21:35:05 +08:00
Redkale
edbc878b73 修复Utility.encodeUTF8Length的bug 2019-09-19 21:22:47 +08:00
Redkale
f706209ec1 RestResult合并进HttpResult 2019-09-19 21:08:36 +08:00
Redkale
bf000b188f 增加RestResult功能 2019-09-19 20:30:30 +08:00
Redkale
def1736a9b 2019-09-19 13:22:56 +08:00
Redkale
0242f4c0c3 2019-09-19 13:22:20 +08:00
Redkale
5cd399b2df 2019-09-19 13:12:33 +08:00
Redkale
9ddb662016 Convert增加BiFunction<Attribute, Object, Object> fieldFunc参数 2019-09-19 12:05:03 +08:00
Redkale
2947275d54 2019-09-18 11:27:54 +08:00
Redkale
e43f814872 Utility增加containsMatch、removeMatch方法 2019-09-18 11:22:28 +08:00
Redkale
6e16f52e28 2019-09-18 11:02:13 +08:00
Redkale
fca13557df 【不兼容】删掉javax.persistence.GeneratedValue功能 2019-09-16 16:35:41 +08:00
Redkale
824a6df55a 2019-09-16 16:29:12 +08:00
Redkale
b98b526c50 2019-09-09 16:35:08 +08:00
Redkale
8f6aa4f4a5 2019-09-09 16:29:48 +08:00
Redkale
00a07a79b2 2019-09-09 16:25:10 +08:00
Redkale
264dfbef2e HttpServlet增加postStart方法 2019-09-04 10:00:29 +08:00
Redkale
2e27814809 2019-09-04 09:22:42 +08:00
Redkale
f767f40e56 StringConvertWrapper 改成 StringWrapper 2019-08-30 15:18:03 +08:00
Redkale
543ecc071a 2019-08-30 10:50:24 +08:00
Redkale
2a14f39495 2019-08-30 09:30:41 +08:00
Redkale
95c8ae2334 2019-08-30 08:05:28 +08:00
Redkale
338ea13828 2019-08-29 17:44:13 +08:00
Redkale
4a8b9e5fec 2019-08-29 16:43:45 +08:00
Redkale
e281cac3d3 2019-08-28 16:15:28 +08:00
Redkale
a495829a3c RestHeader支持InetSocketAddress类型 2019-08-28 14:31:33 +08:00
Redkale
b0deed2a89 WebSocket增加getSncpAddress方法,获取分布式下的sncp地址 2019-08-28 12:56:50 +08:00
Redkale
70a75abf74 Redkale 2.0.0.beta3 结束 2019-08-15 13:11:17 +08:00
Redkale
1aa97f8e79 2019-08-06 10:08:24 +08:00
Redkale
b4000235ac 2019-08-05 17:51:26 +08:00
Redkale
4b93f29a1c 2019-08-05 17:14:14 +08:00
Redkale
4892a50670 2019-08-05 16:26:52 +08:00
Redkale
2fe0ac0ef9 修复ColumnValue.mov时字段类型是long,而参数值是int会报错的bug 2019-07-31 17:19:35 +08:00
Redkale
333ae72148 2019-07-30 11:05:11 +08:00
Redkale
5fd5b7f303 2019-07-30 10:58:37 +08:00
Redkale
528cf45f3f ColumnExpress增加除法、取模表达式 2019-07-30 10:31:48 +08:00
Redkale
c7308e7320 修复ConvertFacotry.register方法中column参数没有对应field时会导致method的ignore失效的bug 2019-07-29 13:20:23 +08:00
Redkale
e2a49eaab7 2019-07-29 11:40:33 +08:00
Redkale
44bd6f235c 2019-07-25 16:58:20 +08:00
Redkale
601d15b513 2019-07-17 19:00:18 +08:00
Redkale
9e93485a97 新增HttpRequest.getQueryBytes方法 2019-07-17 18:42:45 +08:00
Redkale
ad87b2115d 修改多个@RetLabel不能正确根据locale获取对应值的bug 2019-07-17 15:14:48 +08:00
Redkale
27a587d31f 修复mysql下update操作值带转义字符导致失败的bug 2019-07-12 16:52:46 +08:00
Redkale
fc8fa27602 RetResult增加map静态方法 2019-07-11 14:53:51 +08:00
Redkale
f9aebc8ee3 修复同一个Entity类被多个source源分表分库操作时判断表是否已建有误的bug 2019-07-09 14:18:07 +08:00
Redkale
1167da8f4c Redkale 2.0.0.beta2 结束 2019-07-08 09:15:26 +08:00
Redkale
7a5fbcdccd 2019-07-03 11:35:37 +08:00
Redkale
345e929712 [不兼容修改]CacheSource的getCollectionMap序列方法增加一个set参数 2019-06-27 18:21:19 +08:00
Redkale
358862fe59 修复Entity类带boolean字段调DataSource.insert出现异常的bug 2019-06-26 16:51:48 +08:00
Redkale
3dde9bb293 2019-06-21 17:00:40 +08:00
Redkale
99ae4ccadd 从Context中移除BufferPool和ResponsePool 2019-06-20 15:26:20 +08:00
Redkale
98e9ffe0ef 2019-06-20 10:02:24 +08:00
Redkale
6927bfe8ac 2019-06-19 16:52:00 +08:00
Redkale
340a3a8fa3 2019-06-19 16:46:12 +08:00
Redkale
4724763991 2019-06-19 16:45:45 +08:00
Redkale
03353ad08c 2019-06-19 16:21:05 +08:00
Redkale
95c3354fcd WebSocketParam增加getAnnotations系列方法 2019-06-19 15:47:46 +08:00
Redkale
1bda2f92b9 HttpRequest增加getAnnotation系列方法 2019-06-18 22:59:07 +08:00
Redkale
bd3c706934 修复DataSource中json字段不为Serializable时会异常的bug 2019-06-13 22:34:53 +08:00
Redkale
ef3663aa36 修复DataSource中json字段不为Serializable时会异常的bug 2019-06-13 22:23:30 +08:00
Redkale
427ff717d4 UDP协议下bufferCapacity默认值为1350字节 2019-05-30 12:07:09 +08:00
Redkale
b409300412 UDP协议下bufferCapacity默认值为1480字节 2019-05-30 12:04:13 +08:00
Redkale
ca1f974dbe 2019-05-28 17:43:48 +08:00
Redkale
6a8c86096b DataSource的clearTable、dropTable在表不存在的情况下由抛异常改为结果值返回-1 2019-05-28 15:51:59 +08:00
Redkale
2b2fd9965b Redkale 2.0.0.beta1 结束 2019-05-25 10:46:10 +08:00
Redkale
0938635eb2 2019-05-18 08:37:53 +08:00
Redkale
a4a186751e 2019-05-01 08:05:37 +08:00
Redkale
ea5169b5c5 修改mysql中字符串带\会丢失的bug 2019-04-27 11:17:28 +08:00
Redkale
01bd195847 2019-04-26 21:24:02 +08:00
Redkale
a72c26a935 修复Utility.encodeUTF8和decodeUTF8 对4字节字符不能正常编码的bug 2019-04-22 12:24:55 +08:00
Redkale
a9900d9bfa 2019-04-19 19:41:04 +08:00
Redkale
6896401d2d 2019-04-19 19:32:24 +08:00
Redkale
886f01c9f3 DataSource在Cachable定时load时屏蔽log 2019-04-19 19:31:09 +08:00
Redkale
59c9251d70 2019-04-12 12:14:52 +08:00
Redkale
fad5f010d2 2019-04-12 11:57:21 +08:00
Redkale
737c4a92b9 修复ConvertFactory.registerIgnoreAll方法出现不生效的bug 2019-04-04 22:20:16 +08:00
Redkale
d3e8675948 Redkale 2.0.0.alpha2 开始 2019-04-04 22:18:49 +08:00
Redkale
a4ffc7a27c 2019-03-30 20:23:55 +08:00
Redkale
91bf7b1387 2019-03-30 17:28:25 +08:00
Redkale
1396296337 2019-03-29 11:51:19 +08:00
Redkale
e4672355fc Convert增加StringConvertWrapper功能 2019-03-29 11:44:37 +08:00
Redkale
129ed25ca4 2019-03-29 09:08:16 +08:00
Redkale
e6d7e5fe98 2019-03-28 17:36:31 +08:00
Redkale
73ce5fa11f Convert支持AbstractMap.SimpleEntry 2019-03-28 14:56:28 +08:00
Redkale
ce01c3d4ce 2019-03-22 12:21:38 +08:00
Redkale
3b3de316ea 2019-03-21 14:19:35 +08:00
Redkale
8c739ce54d 2019-03-16 12:58:54 +08:00
Redkale
0aa4d6c967 2019-03-15 10:19:00 +08:00
Redkale
d7a3f4d87d 2019-03-14 21:25:14 +08:00
Redkale
fe9e074581 2019-03-14 17:00:22 +08:00
Redkale
40813e8752 2019-03-14 16:17:43 +08:00
Redkale
e90f2e4142 WebSocket增加mergemsg属性功能 2019-03-14 15:27:05 +08:00
Redkale
2a19ea709b 2019-03-14 13:47:57 +08:00
Redkale
30c9be303f Convert增加ConvertMask[]参数方法 2019-03-14 13:17:31 +08:00
Redkale
e101b79472 修复ws数据包过大粘包的bug 2019-03-14 12:32:07 +08:00
Redkale
8ad919f952 修复了Convert在忽略子类某些字段时因为Method导致无法忽略父类的getter方法的bug 2019-03-06 09:31:18 +08:00
Redkale
294543c46e 取消DataSource兼容找不到unitName时使用第一个配置的功能 2019-03-05 20:16:57 +08:00
Redkale
79f8363d47 2019-03-05 12:23:21 +08:00
Redkale
6d3553b0b5 2019-02-12 13:16:43 +08:00
Redkale
403ab4e281 2019-02-12 12:23:03 +08:00
Redkale
87e7c43032 修复JDK9+以上RedkaleClassLoader的getAllURLS方法中的BUG 2019-02-12 11:52:23 +08:00
Redkale
a321b41699 2019-01-19 16:28:44 +08:00
Redkale
fea34863e3 2019-01-18 22:25:20 +08:00
Redkale
bcaf7ab73e 2019-01-18 19:48:32 +08:00
Redkale
b9d7eaee1b 2019-01-18 18:52:47 +08:00
Redkale
d605045858 2019-01-18 16:55:48 +08:00
Redkale
cf2ab617c2 修复AioAsyncConnection关闭时write队列还有数据没写完的bug 2019-01-18 15:50:23 +08:00
Redkale
204514cb08 增加Utility.nowMillis方法 2019-01-18 10:41:30 +08:00
Redkale
cfe01cca75 2019-01-16 19:04:54 +08:00
Redkale
ac294c58ae 2019-01-16 19:01:48 +08:00
Redkale
6950eb2f30 2019-01-13 16:51:06 +08:00
Redkale
847f81374b 2019-01-12 11:44:50 +08:00
Redkale
bb09aea8bb 2019-01-12 11:28:29 +08:00
Redkale
2e1ff333f5 Application.singleton多加一个参数,指定其他Service也被加载 2019-01-12 11:16:27 +08:00
Redkale
c14a2b4011 updateColumnCompose 2019-01-12 11:15:02 +08:00
Redkale
d9c6c3d2d0 2019-01-11 16:51:21 +08:00
Redkale
91d4477ed9 DataSource增加字段加解密功能,主类:CryptColumn/CryptHandler 2019-01-11 16:41:14 +08:00
Redkale
623c0a127e Attribute增加attach方法 2019-01-11 15:22:29 +08:00
Redkale
bc64666700 Reproduce.create方法中BiPredicate参数的第一个泛型改为AccessibleObject 2019-01-10 18:43:45 +08:00
Redkale
5c7dd7d782 2019-01-09 16:17:48 +08:00
Redkale
e78a2da6c0 2019-01-09 16:16:08 +08:00
Redkale
065be6f3d7 增加RetResult.success(V result)方法 2019-01-09 09:44:53 +08:00
Redkale
874f3330b8 Update README.md 2019-01-08 14:33:41 +08:00
Redkale
684edfa10b 2019-01-08 12:54:09 +08:00
Redkale
e69a120965 2019-01-08 12:46:20 +08:00
Redkale
4a36244294 2019-01-08 12:39:21 +08:00
Redkale
cb444be0f7 优化Application.singleton方法 2019-01-08 12:32:47 +08:00
Redkale
8b5cbf186f 2019-01-08 09:13:05 +08:00
Redkale
dbc6f8a196 2019-01-07 21:38:44 +08:00
Redkale
9b94604166 2019-01-07 21:17:20 +08:00
Redkale
cc98a85711 2019-01-07 21:09:22 +08:00
Redkale
6855d06f55 JsonConvert增加不带Type参数的convertTo方法 2019-01-07 20:07:36 +08:00
Redkale
89d90ddf5b 修复getHttpContent会变成POST请求的bug 2019-01-07 17:05:02 +08:00
Redkale
6280111121 2019-01-05 09:42:03 +08:00
Redkale
231d41c15f DataSource增加清空表clear和删除表drop的系列方法 2019-01-04 14:26:20 +08:00
Redkale
cfca7adc66 2019-01-03 18:38:07 +08:00
Redkale
aedd215de4 2019-01-03 18:33:49 +08:00
Redkale
df8e839580 优化WebSocket给多个userid发消息的实现 2019-01-03 09:35:28 +08:00
Redkale
300441b9f7 DataSource增加getCollectionMap系列接口 2019-01-03 09:33:19 +08:00
Redkale
1a5e9022ae Convert支持java.time.Duration 2019-01-03 09:07:26 +08:00
Redkale
2a3b8f87d3 兼容@Resource标记在泛型类型字段上 2019-01-03 09:06:08 +08:00
Redkale
b7930f1ed7 Redkale 2.0.0 开始 2019-01-03 09:05:00 +08:00
Redkale
a78c2145e6 2018-12-24 17:16:39 +08:00
Redkale
ee20a34a70 2018-12-24 14:52:05 +08:00
Redkale
33bd80c572 2018-12-22 15:16:00 +08:00
Redkale
031309b105 2018-12-22 15:08:56 +08:00
Redkale
bcbd981a9b 2018-12-21 10:55:20 +08:00
Redkale
b7ce390c33 WebServlet.value带.不视为正则表达式 2018-12-21 10:38:37 +08:00
Redkale
c9d099c694 2018-12-20 17:22:16 +08:00
Redkale
fcca0329c6 2018-12-20 13:55:46 +08:00
Redkale
c82c0bc680 2018-12-20 11:51:12 +08:00
Redkale
2921478a0a 2018-12-20 11:38:11 +08:00
Redkale
61a5420d48 兼容泛型嵌套 2018-12-19 18:38:28 +08:00
Redkale
702ab6ef6e 2018-12-19 16:03:11 +08:00
Redkale
2576e71a7d 2018-12-19 11:33:08 +08:00
Redkale
0d0bd78213 2018-12-18 15:20:13 +08:00
Redkale
8d9fa8f9cf 2018-12-18 14:15:27 +08:00
Redkale
25eaf6e353 AsyncConnection接口大变动 2018-12-18 14:04:49 +08:00
Redkale
8afcaa0b34 2018-12-18 09:41:20 +08:00
Redkale
1824f8150c 2018-12-17 10:57:49 +08:00
Redkale
2f89778fd6 2018-12-17 10:56:00 +08:00
Redkale
f9d250b43c 2018-12-17 10:29:23 +08:00
Redkale
3a3c09d8aa 2018-12-15 15:07:46 +08:00
Redkale
09a0d4f9e2 2018-12-15 15:06:24 +08:00
Redkale
3bba781183 WATCH服务增加功能:更改Server的监听地址和端口 2018-12-13 13:47:44 +08:00
Redkale
6426f8fe91 2018-12-11 19:46:31 +08:00
Redkale
5906594148 2018-12-11 18:58:15 +08:00
Redkale
1b188c863c 2018-12-10 19:51:31 +08:00
Redkale
087b4cb571 2018-12-10 19:47:26 +08:00
Redkale
c9496b6231 application.xml中source节点兼容DataJdbcSource 2018-12-10 19:44:56 +08:00
Redkale
60d95d7628 2018-12-06 21:29:55 +08:00
Redkale
dd9e7e77b5 2018-12-06 21:06:21 +08:00
Redkale
50c9363876 2018-12-05 17:59:56 +08:00
Redkale
938e357745 2018-12-03 09:04:27 +08:00
Redkale
08ee51f8ab 2018-12-01 14:22:30 +08:00
Redkale
40ae555645 2018-11-29 14:09:18 +08:00
Redkale
33f89264a6 2018-11-29 13:54:14 +08:00
Redkale
e4ea20cc5f 2018-11-28 14:33:55 +08:00
Redkale
045b7db1af 修复JsonConvert的""空字符串转换对象抛异常的BUG 2018-11-28 14:23:10 +08:00
Redkale
676c1b5d21 修复JsonConvert的""空字符串转换对象抛异常的BUG 2018-11-28 14:22:00 +08:00
Redkale
e4319246b8 2018-11-28 14:04:07 +08:00
Redkale
32d8515bf4 DataSource增加部分JSON功能 2018-11-28 11:17:55 +08:00
Redkale
d7e7113201 Sncp的部分Attribute.type()改为genericType方法 2018-11-28 09:18:12 +08:00
Redkale
9493aa43a7 Attribute增加genericType方法 2018-11-28 09:12:58 +08:00
Redkale
d07c55b831 【不兼容】BSON格式升级,兼容子类数据转父类对象 2018-11-27 15:10:19 +08:00
Redkale
47dab88d72 调整Convert部分内部接口 2018-11-27 14:10:58 +08:00
Redkale
9e553aeff6 修复JsonReader.readSmallString() BUG 2018-11-27 11:48:50 +08:00
Redkale
ed8e754557 兼容ColumnValue...含null的情况 2018-11-24 14:20:06 +08:00
Redkale
651dc3df2a 还原 2018-11-22 14:47:58 +08:00
Redkale
84e5bc3437 2018-11-22 14:46:55 +08:00
Redkale
64fd0176ac 兼容手动new XXXService字段inject时抛异常 2018-11-22 14:45:24 +08:00
Redkale
c1f3115d4e 2018-11-20 10:55:09 +08:00
Redkale
1c70834760 2018-11-19 17:33:33 +08:00
Redkale
7c901731bc Bson的skipValue方法支持部分常规Collection<JavaBean>、Map<String, JavaBean>字段类型 2018-11-19 15:32:24 +08:00
Redkale
2b2d53e515 Bson的skipValue方法支持部分常规Collection、Map字段类型 2018-11-19 15:14:48 +08:00
Redkale
be051ecf45 Redkale 1.9.9 开始 2018-11-19 15:12:20 +08:00
Redkale
18534eb654 2018-11-08 16:08:48 +08:00
Redkale
a5a926fd94 FilterNode、FilterJoinNode增加copy方法 2018-10-18 14:47:07 +08:00
Redkale
0cb9f2cad3 2018-10-17 08:18:23 +08:00
Redkale
98209cc82e 修改WebSocketNode.existsWebSocket的实现 2018-10-10 14:03:54 +08:00
Redkale
1879afa6a4 2018-10-09 16:34:35 +08:00
Redkale
4a6404dfec 2018-09-27 09:54:42 +08:00
Redkale
0fa1c4a08f 修复WebSocket中Connection重复的bug 2018-09-27 09:51:44 +08:00
Redkale
573d7c5776 修复Rest.createRestWebSocketServlet空指针bug 2018-09-26 17:23:19 +08:00
Redkale
c56c9bf260 Redkale 1.9.8 开始 2018-09-26 17:21:33 +08:00
Redkale
387865789f 2018-09-20 16:03:33 +08:00
Redkale
03fcf43a89 2018-09-19 11:11:59 +08:00
Redkale
df8090813a 2018-09-12 12:11:19 +08:00
Redkale
849b29d00f CacheSource的增删改查操作增加Type参数 2018-09-12 12:04:59 +08:00
Redkale
4b7f65e1c4 2018-09-11 14:29:42 +08:00
Redkale
4545d81e50 2018-09-11 11:12:43 +08:00
Redkale
1ac5f060a4 增加WebSocketAction功能 2018-09-11 09:13:19 +08:00
Redkale
7e1ff8e315 2018-09-10 17:23:23 +08:00
Redkale
4e0c1fee97 2018-09-10 14:02:26 +08:00
Redkale
0b38f23f2d 2018-09-10 14:01:56 +08:00
Redkale
98ea6861c1 2018-09-10 10:44:03 +08:00
Redkale
c07b628ea1 FilterNode增加readonly属性 2018-09-07 10:21:48 +08:00
Redkale
b1b979c0b5 优化Rest.createRestServlet减少preInit的耗时 2018-09-07 09:20:52 +08:00
Redkale
35b708b01d 2018-09-07 08:50:20 +08:00
Redkale
229ae0d44f 2018-09-06 18:17:11 +08:00
Redkale
7d6897fa36 2018-09-06 14:33:53 +08:00
Redkale
5851093590 2018-09-05 16:58:19 +08:00
Redkale
4646c1d1f0 2018-09-05 16:57:09 +08:00
Redkale
f3763dbf72 2018-09-05 16:41:44 +08:00
Redkale
6a8c60ec78 优化NodeHttpServer.loadRestServlet 2018-09-05 16:15:21 +08:00
Redkale
ae437fd5d6 优化Rest.createRestServlet 2018-09-05 15:53:54 +08:00
Redkale
7251c984c8 修复FilterNode.findValue的bug 2018-09-05 11:00:47 +08:00
Redkale
ec449220eb 2018-09-05 09:49:20 +08:00
Redkale
78265944f0 2018-09-05 09:23:41 +08:00
Redkale
d2791f6d1b 2018-09-05 08:29:58 +08:00
Redkale
d525d2664b 2018-08-31 10:39:43 +08:00
Redkale
a4ccea91ad 修复FilterJoinNode.any方法bug 2018-08-29 16:06:41 +08:00
Redkale
750da161eb 增强HttpUserType的类型校验 2018-08-28 10:18:27 +08:00
Redkale
ac50312f0b 2018-08-27 18:28:56 +08:00
Redkale
8d44d48072 2018-08-27 18:26:16 +08:00
Redkale
6c2baa1708 增加RestConvertCoder功能 2018-08-27 18:25:08 +08:00
Redkale
4525cfe594 2018-08-27 12:36:35 +08:00
Redkale
921f96c975 优化toBuffers方法 2018-08-27 12:29:59 +08:00
Redkale
29ce57d3af BsonWriter.toBuffers存在并发问题 2018-08-27 12:07:45 +08:00
Redkale
2ca1e6305c 修改HttpResponse.finish(byte[]) 2018-08-27 11:55:36 +08:00
Redkale
827b404a57 Update application.xml 2018-08-25 13:35:48 +08:00
Redkale
83569142c1 2018-08-25 13:12:24 +08:00
Redkale
2da0faacc3 2018-08-24 16:24:58 +08:00
Redkale
cf51bee2cc 2018-08-24 16:07:19 +08:00
Redkale
0dd55dc947 2018-08-24 16:04:49 +08:00
Redkale
620fa0430c ClassFilter输出更详细日志 2018-08-23 19:54:47 +08:00
Redkale
d053590257 增加JDK9+环境下显示进程PID功能 2018-08-23 19:28:20 +08:00
Redkale
684af3de61 application.xml的properties值支持${APP_HOME} 2018-08-23 09:59:14 +08:00
Redkale
6c6e26ed0b 2018-08-22 10:37:49 +08:00
Redkale
4a05bfbd08 2018-08-22 10:34:48 +08:00
Redkale
787dc7b32f 2018-08-22 10:03:20 +08:00
Redkale
85a1f99f6e 2018-08-22 09:42:51 +08:00
Redkale
4fe8a1199e 修复CollectionDecoder的creator指定错误的bug 2018-08-22 09:30:11 +08:00
Redkale
7312dbc4c5 增加H2数据库的支持 2018-08-21 10:06:05 +08:00
Redkale
cfecfabc92 createRestServlet兼容throws IOException和RuntimeException的子类 2018-08-20 17:28:34 +08:00
Redkale
587160c5fe Redkale 1.9.7 开始 2018-08-20 17:23:13 +08:00
Redkale
ee7fe3ed33 2018-08-20 16:49:39 +08:00
Redkale
47d4a6cc29 2018-08-20 14:42:16 +08:00
Redkale
c1e4763369 2018-08-20 14:28:02 +08:00
Redkale
333ba0f162 2018-08-18 11:27:50 +08:00
Redkale
e039b0e9f6 2018-08-17 11:26:45 +08:00
Redkale
b3c5e3beca 2018-08-15 18:18:27 +08:00
Redkale
70ba45c3bd 2018-08-15 18:13:09 +08:00
Redkale
14ae44fcac 修复DataJdbcSource.queryList会查total的BUG 2018-08-15 16:57:44 +08:00
Redkale
f7618f5da4 DataSqlSource.directQuery接口变动 2018-08-15 14:49:20 +08:00
Redkale
d6c6e4c02e 2018-08-14 10:40:11 +08:00
Redkale
9365052b85 2018-08-13 19:20:21 +08:00
Redkale
ef88063094 修复EntityCache重复insert数据时会导致map和list的同一id的对象不一致的BUG 2018-08-13 19:12:05 +08:00
Redkale
4cbaf85eea 2018-08-13 18:30:07 +08:00
Redkale
6c07123da3 2018-08-13 18:29:12 +08:00
Redkale
04a4ce12c7 2018-08-09 19:32:03 +08:00
Redkale
e00ed8ae37 增加DataMemorySource 2018-08-08 14:30:51 +08:00
Redkale
218a79b60a 2018-08-07 15:41:22 +08:00
Redkale
19ae86c71f 2018-08-07 13:52:00 +08:00
Redkale
9250d4e64d 2018-08-07 11:53:26 +08:00
Redkale
9f5aa58a31 2018-08-06 19:58:19 +08:00
Redkale
c8b0a88573 2018-08-06 18:05:13 +08:00
Redkale
7cf3f49aa1 1.9.5.1 2018-08-06 17:39:17 +08:00
Redkale
be2c803f82 2018-08-06 17:38:03 +08:00
Redkale
fd1197e8dc 2018-08-04 23:40:52 +08:00
Redkale
115f91b64a 2018-08-04 18:31:29 +08:00
Redkale
dfb800473a 2018-08-04 18:08:11 +08:00
Redkale
c69c1bb134 ppl 2018-08-04 15:12:22 +08:00
Redkale
5b501c7c2f 2018-08-04 14:52:44 +08:00
Redkale
8d5ce56ec2 FileHandler.limit支持G/M/K 2018-08-03 22:23:56 +08:00
Redkale
15c97ddc18 2018-08-02 13:51:41 +08:00
Redkale
36d7fbf4e9 2018-07-31 15:47:18 +08:00
Redkale
919e7aa5c6 2018-07-30 16:02:26 +08:00
Redkale
2174de2b71 2018-07-30 16:01:39 +08:00
Redkale
cb9e914e44 2018-07-30 15:51:20 +08:00
Redkale
15f856b762 2018-07-30 15:26:47 +08:00
Redkale
991dba0d62 2018-07-27 21:29:50 +08:00
Redkale
aa2685d6e4 修复WebSocketEngine的future = future.whenComplete问题 2018-07-27 20:35:48 +08:00
Redkale
0952150328 2018-07-27 20:29:13 +08:00
Redkale
e6ef4d1546 2018-07-27 20:02:08 +08:00
Redkale
16cf85abb9 2018-07-27 19:59:58 +08:00
Redkale
5afe0ead94 修复WebSocketNode远程模式下forceCloseWebSocket会报错的BUG 2018-07-27 19:52:12 +08:00
Redkale
b6c933f989 WebSocketNode远程模式下forceCloseWebSocket会报错 2018-07-27 19:38:46 +08:00
Redkale
feaf1a1f06 Redkale 1.9.6 开始 2018-07-27 19:19:00 +08:00
Redkale
6b54c6e886 2018-07-26 16:16:09 +08:00
Redkale
a95b69ab79 2018-07-26 11:54:09 +08:00
Redkale
a2492ae248 2018-07-26 11:36:51 +08:00
Redkale
0db1c4413c 2018-07-26 10:53:35 +08:00
Redkale
8718bca6e8 2018-07-26 08:48:23 +08:00
Redkale
6486863d00 2018-07-25 16:36:09 +08:00
Redkale
bfc2397dbf 2018-07-25 14:58:02 +08:00
Redkale
0cfdb9795b 2018-07-25 12:06:11 +08:00
Redkale
d327757d59 2018-07-25 11:43:51 +08:00
Redkale
e88c4fa2e3 修复进程关闭时WebSocket没有执行onClose方法的BUG 2018-07-24 20:11:02 +08:00
Redkale
69a0071e17 2018-07-23 10:06:36 +08:00
Redkale
d3cfe809e7 2018-07-23 09:38:47 +08:00
Redkale
0ca6e5401a 2018-07-23 09:37:49 +08:00
Redkale
8ff2b60ed4 2018-07-22 18:37:07 +08:00
Redkale
1dbe125e27 2018-07-22 18:15:24 +08:00
Redkale
32a595262d 2018-07-22 18:03:30 +08:00
Redkale
01431a93a4 2018-07-22 17:55:02 +08:00
Redkale
00a12d8113 2018-07-21 14:21:50 +08:00
Redkale
0f2474386c 2018-07-21 10:58:17 +08:00
Redkale
5de52ed6e8 Convert优化 2018-07-21 10:50:01 +08:00
Redkale
099b3fb7f3 2018-07-20 15:00:18 +08:00
Redkale
ed85e33403 2018-07-20 11:38:53 +08:00
Redkale
daff7d095f 2018-07-20 10:58:51 +08:00
Redkale
a8ff82229f 2018-07-20 10:01:59 +08:00
Redkale
2874e7d195 2018-07-20 09:48:47 +08:00
Redkale
8baea2657d 2018-07-20 09:04:05 +08:00
Redkale
03e9a5cbcb 更新Convert的Array、Map相关接口 2018-07-19 10:26:40 +08:00
Redkale
8d2f2a28af 2018-07-18 16:14:09 +08:00
Redkale
4a4bade180 Decoder/Encoder获取更多信息 2018-07-16 19:16:10 +08:00
Redkale
28e72f9883 Convert增加readByteArray和writeByteArray方法 2018-07-16 18:38:02 +08:00
Redkale
681e3967d2 2018-07-16 14:02:30 +08:00
Redkale
640dcbc8d7 2018-07-16 12:40:32 +08:00
Redkale
19276ecb91 2018-07-16 00:36:45 +08:00
Redkale
9f9078cdc5 2018-07-16 00:33:45 +08:00
Redkale
9bd1e0c97b 2018-07-15 23:42:28 +08:00
Redkale
c2c8f700a2 2018-07-15 22:18:52 +08:00
Redkale
86895eb5ef 2018-07-15 20:10:09 +08:00
Redkale
e8dacd6b70 2018-07-15 18:11:30 +08:00
Redkale
03fcf1dc95 2018-07-15 17:43:58 +08:00
Redkale
953b2be224 2018-07-14 12:54:48 +08:00
Redkale
55645ba2a0 2018-07-14 09:22:42 +08:00
Redkale
858c6a0aaf 2018-07-14 00:14:10 +08:00
Redkale
85d4023fa2 2018-07-13 23:22:02 +08:00
Redkale
607fc8e45f 2018-07-13 23:13:42 +08:00
Redkale
511a966ce5 2018-07-13 23:11:36 +08:00
Redkale
6d135efbc6 2018-07-13 22:56:33 +08:00
Redkale
5dff6310aa 2018-07-13 11:52:28 +08:00
Redkale
194a06c748 2018-07-13 09:41:26 +08:00
Redkale
1ce97aa20d 2018-07-13 06:46:55 +08:00
Redkale
1c88fb0355 修复JsonConvert没有按指定Type进行convertTo的BUG 2018-07-12 17:45:41 +08:00
Redkale
7b81c42377 JsonConvert支持带空格的数值字符串转成Number对象 2018-07-12 14:19:40 +08:00
Redkale
1afa38a947 2018-07-11 16:58:03 +08:00
Redkale
eedb418299 增加RpcRemoteException 2018-07-11 16:15:24 +08:00
Redkale
9efc14e627 2018-07-10 15:36:23 +08:00
Redkale
0dc3d65307 去掉对Rest中find、delete开头方法的特殊处理 2018-07-10 15:25:40 +08:00
Redkale
e3ddbe609c 2018-07-09 11:10:15 +08:00
Redkale
f115934499 2018-07-08 14:49:48 +08:00
Redkale
f5e290a47a Watch组件增加可以获取指定Servie中某个可序列化的字段的值 2018-07-06 22:28:20 +08:00
Redkale
29cd395888 RestConvert增加可以返回skipAllIgnore(true)的Convert功能 2018-07-06 18:53:39 +08:00
Redkale
9ca7855756 2018-07-05 11:47:58 +08:00
Redkale
1f1ab112eb 2018-07-05 11:36:30 +08:00
Redkale
b172b66263 去掉persistence.xml的监听文件变化功能,该有watch组件提供动态修改数据源配置 2018-07-05 09:49:19 +08:00
Redkale
b08f9f5757 增加java.util.Properties的convert 2018-07-05 09:47:39 +08:00
Redkale
32e65ff304 2018-07-03 15:49:32 +08:00
Redkale
40126c923e 2018-07-03 15:09:40 +08:00
Redkale
83ae5b0a13 2018-07-03 15:05:54 +08:00
Redkale
aea6a2839d 增加LogExcludeLevel功能 2018-07-03 10:10:52 +08:00
Redkale
6211d9ff18 Redkale 1.9.5 开始 2018-07-03 09:28:17 +08:00
Redkale
0e7fab71b8 2018-06-28 09:01:33 +08:00
Redkale
a106c8ed60 2018-06-26 16:35:12 +08:00
Redkale
ae52d0ab3d 2018-06-26 16:30:47 +08:00
Redkale
c993cd5b5a Json.writeChar以'A'形式输出 2018-06-25 19:38:32 +08:00
Redkale
9bdd83cc6e 2018-06-25 18:46:53 +08:00
Redkale
1b6a23c1a9 增加APP_CONF配置项,在启动脚本中可以指定配置目录 2018-06-22 16:38:24 +08:00
Redkale
2703d94b83 修复Convert中泛型与非泛型类型并存的问题 2018-06-20 15:58:10 +08:00
Redkale
4cb51ecbe6 2018-06-20 15:48:08 +08:00
Redkale
0cf64121ae 2018-06-12 16:52:09 +08:00
Redkale
58eb3c5d64 AsyncConnection.write调整 2018-06-12 09:15:32 +08:00
Redkale
3c645b4c7f 修复Rest部分情况下获取不到参数的BUG 2018-06-09 10:15:49 +08:00
Redkale
a540eed0ed Redkale 1.9.4 开始 2018-06-09 09:48:50 +08:00
Redkale
ad567b4c40 2018-06-04 18:04:27 +08:00
Redkale
6f8aeea870 2018-06-04 17:59:21 +08:00
Redkale
87a1a7c641 2018-06-04 09:39:46 +08:00
Redkale
178f96a3b5 2018-06-04 08:24:48 +08:00
Redkale
cc629a1a7c 2018-06-02 22:47:13 +08:00
Redkale
1cb72df52e 2018-06-02 22:34:34 +08:00
Redkale
4c32422493 RestWebSocket增加wsthreads属性配置 2018-06-02 15:49:10 +08:00
Redkale
7361823ece 2018-06-02 09:17:34 +08:00
Redkale
03824a900c 2018-06-01 18:35:56 +08:00
Redkale
c40913d690 2018-06-01 12:13:05 +08:00
Redkale
bdfdf153f7 2018-06-01 10:31:00 +08:00
Redkale
fa9e62d2a7 2018-06-01 10:00:59 +08:00
Redkale
bcca20dbbb 2018-05-31 17:12:18 +08:00
Redkale
bca42ee7b4 2018-05-31 15:21:48 +08:00
Redkale
d5f2bae47c 2018-05-31 15:15:08 +08:00
Redkale
fe1e99c67c 2018-05-31 11:34:50 +08:00
Redkale
699d55d70e 2018-05-31 10:23:16 +08:00
Redkale
3d11a95a29 2018-05-31 09:13:15 +08:00
Redkale
a983c53189 2018-05-31 09:02:55 +08:00
Redkale
0ee28f59ce 2018-05-31 08:47:49 +08:00
Redkale
96ee0584b8 2018-05-30 19:48:17 +08:00
Redkale
7352d5b8ed 2018-05-30 19:47:21 +08:00
Redkale
e79fdd887c 2018-05-30 19:43:46 +08:00
Redkale
7b5b0f34ff 2018-05-30 18:54:02 +08:00
Redkale
ae8fb992fb 2018-05-30 18:48:52 +08:00
Redkale
d5409518ed 2018-05-30 18:45:01 +08:00
Redkale
6bb2e152a5 2018-05-30 18:23:12 +08:00
Redkale
c73ebf88db 2018-05-29 09:35:15 +08:00
Redkale
bfdceec81b 2018-05-29 09:31:03 +08:00
Redkale
dd444e3a0f 2018-05-28 22:13:50 +08:00
Redkale
79de8dbbca 2018-05-28 17:38:41 +08:00
Redkale
5c6f3c3712 2018-05-28 17:27:10 +08:00
Redkale
0d0663a7de 2018-05-28 17:19:06 +08:00
Redkale
6d1c4e6c85 2018-05-28 10:10:59 +08:00
Redkale
f539633497 2018-05-28 10:01:17 +08:00
Redkale
d9ddd6d772 2018-05-28 09:59:39 +08:00
Redkale
4a2ba4e914 2018-05-26 09:58:34 +08:00
Redkale
cc864e3e69 2018-05-25 15:31:43 +08:00
Redkale
4cd5bd37d3 2018-05-24 10:09:35 +08:00
Redkale
ff14e675fa 2018-05-23 18:20:30 +08:00
Redkale
a46cb462a2 2018-05-23 09:28:33 +08:00
Redkale
8077dedd03 2018-05-22 09:50:38 +08:00
Redkale
6a707dff0c 2018-05-21 14:38:07 +08:00
Redkale
c9aa31d803 2018-05-21 13:57:25 +08:00
Redkale
4494683db2 2018-05-21 12:04:15 +08:00
Redkale
f440b2d639 2018-05-21 11:54:52 +08:00
Redkale
324d4bd94e 2018-05-20 13:14:41 +08:00
Redkale
bb82d70f5a 2018-05-20 12:34:53 +08:00
Redkale
8d1022f70f 2018-05-19 14:58:31 +08:00
Redkale
00034981ef 2018-05-19 13:07:36 +08:00
Redkale
2b3b33979c 2018-05-19 11:34:31 +08:00
Redkale
8e0788ccf3 2018-05-19 10:51:30 +08:00
Redkale
6e81541a3b 2018-05-19 10:19:41 +08:00
Redkale
6acb17da7c 2018-05-18 17:41:51 +08:00
Redkale
774286952b 2018-05-18 15:20:37 +08:00
Redkale
35a3c81391 2018-05-18 15:11:18 +08:00
Redkale
90d28eb4f4 2018-05-18 14:58:13 +08:00
Redkale
aab24fdbbe 2018-05-18 12:29:07 +08:00
Redkale
d0c24ed7a7 2018-05-18 12:25:49 +08:00
Redkale
2260906396 2018-05-17 19:51:02 +08:00
Redkale
0901195147 2018-05-17 19:49:27 +08:00
Redkale
c11a8e7bd9 2018-05-17 19:48:48 +08:00
Redkale
8176ec1b0a 2018-05-17 19:42:34 +08:00
Redkale
8f598fe4eb 2018-05-17 17:58:23 +08:00
Redkale
2fac5c853e 2018-05-17 17:46:32 +08:00
Redkale
4dbd6b57f8 2018-05-17 17:41:52 +08:00
Redkale
a5f21a99d8 2018-05-17 17:35:47 +08:00
Redkale
6f98b44471 2018-05-17 17:20:08 +08:00
Redkale
b13b07fb05 2018-05-17 17:06:57 +08:00
Redkale
1f8884a415 2018-05-12 15:46:33 +08:00
Redkale
848a30b2db 2018-05-12 14:35:34 +08:00
Redkale
350ece1533 2018-05-12 14:24:59 +08:00
Redkale
513183f55c 2018-05-11 17:38:11 +08:00
Redkale
b23434e3bb 2018-05-11 16:22:51 +08:00
Redkale
7084fb2ea2 2018-05-11 08:18:50 +08:00
Redkale
5becdf4d50 切换DataJdbcSource 2018-05-10 19:44:51 +08:00
Redkale
5aa10e9d74 切换DataJdbcSource 2018-05-10 19:39:47 +08:00
Redkale
db462ec134 2018-05-10 19:39:00 +08:00
Redkale
75e9f6162b 2018-05-10 19:22:35 +08:00
Redkale
970d530fbd 2018-05-10 10:25:33 +08:00
Redkale
13ffa2a3e5 2018-05-09 16:19:00 +08:00
Redkale
8416826827 2018-05-09 15:53:34 +08:00
Redkale
0a296ee857 2018-05-09 09:23:43 +08:00
Redkale
bb45470078 2018-05-07 17:03:39 +08:00
Redkale
d3c6ab8dc5 2018-05-07 12:44:55 +08:00
Redkale
0bf34781c5 2018-05-07 11:46:05 +08:00
Redkale
20940e82de 2018-05-06 18:23:38 +08:00
Redkale
78df572bec 2018-05-06 18:20:23 +08:00
Redkale
ffd0bec5c6 2018-05-06 16:54:46 +08:00
Redkale
62783d0765 2018-05-06 16:38:41 +08:00
Redkale
7116f33a3a 2018-05-06 07:50:50 +08:00
Redkale
a168dab8c0 2018-05-05 16:05:48 +08:00
Redkale
e3e065f36e 2018-05-05 13:23:42 +08:00
Redkale
d282321d98 2018-05-05 11:43:32 +08:00
Redkale
1abdb3b874 2018-05-05 11:22:26 +08:00
Redkale
1807287321 2018-05-05 10:29:55 +08:00
Redkale
a29652180b 2018-05-05 06:21:23 +08:00
Redkale
d4a85ac136 2018-05-04 21:03:40 +08:00
Redkale
007f635081 2018-05-04 20:30:54 +08:00
Redkale
f75e15a375 2018-05-04 20:29:40 +08:00
Redkale
508c7c4c0a 2018-05-04 20:23:08 +08:00
Redkale
7166dc0ec0 2018-05-04 17:31:45 +08:00
Redkale
1f28b7e803 2018-05-04 15:26:07 +08:00
Redkale
5d77139965 2018-05-04 15:17:59 +08:00
Redkale
126dab08b2 2018-05-04 12:53:16 +08:00
Redkale
a8175d9e19 2018-05-04 11:18:46 +08:00
Redkale
a5c11b5119 2018-05-04 10:26:44 +08:00
Redkale
bfc6b04a30 2018-05-04 08:50:17 +08:00
Redkale
a5dd878c66 2018-05-03 21:15:48 +08:00
Redkale
ed7ce80565 2018-05-03 21:04:23 +08:00
Redkale
e6b71a3975 2018-05-03 20:10:19 +08:00
Redkale
ff5049edc9 2018-05-03 15:33:38 +08:00
Redkale
a34218367b 2018-05-03 09:52:50 +08:00
Redkale
f712107fb8 2018-05-02 20:46:38 +08:00
Redkale
fb3dd6049d 2018-05-02 20:28:03 +08:00
Redkale
13bd467152 2018-05-02 14:59:57 +08:00
Redkale
d934f615ca 2018-05-02 09:22:10 +08:00
Redkale
5e5280a7fd 2018-05-02 08:28:18 +08:00
Redkale
be2a4d252f 2018-05-02 08:13:14 +08:00
Redkale
0392fd68a8 2018-05-01 12:14:52 +08:00
Redkale
e642854e99 2018-05-01 11:54:04 +08:00
Redkale
1a42292725 2018-05-01 10:58:59 +08:00
Redkale
c523a761c5 2018-04-30 14:27:15 +08:00
Redkale
a416ae564a 2018-04-30 14:14:54 +08:00
Redkale
ecd647ecc4 修复Keep-Alive的HTTP请求返回响应包中没有包含Keep-Alive的信息的 2018-04-30 09:37:17 +08:00
Redkale
50d0096492 2018-04-28 22:05:35 +08:00
Redkale
1a2d43479f 2018-04-28 21:57:34 +08:00
Redkale
2416e93004 2018-04-28 21:44:03 +08:00
Redkale
db99445878 2018-04-28 21:36:46 +08:00
Redkale
18459b71c2 2018-04-28 20:43:11 +08:00
Redkale
16cbabc79d 2018-04-28 20:06:12 +08:00
Redkale
c470d31605 2018-04-28 20:03:01 +08:00
Redkale
cdacc30633 2018-04-28 19:56:29 +08:00
Redkale
e55d4d8a78 不含#且方法不超过6个的RestService转换RestServlet采用枚举方式列出@WebServlet.value 2018-04-28 19:32:02 +08:00
Redkale
fcd3258a73 Source增加部分CompletableFuture异常写入日志的功能 2018-04-28 09:04:08 +08:00
Redkale
a8e9822381 2018-04-27 19:00:44 +08:00
Redkale
dfdb37973f 自动注册WebSocketNode 2018-04-27 17:45:56 +08:00
Redkale
3f340a3f7e 2018-04-25 11:38:05 +08:00
Redkale
e64d522707 2018-04-20 20:54:36 +08:00
Redkale
6c05a4a038 2018-04-20 08:58:27 +08:00
Redkale
5c9279cca4 增加Http响应包中Date头的可配置功能 2018-04-19 14:43:47 +08:00
Redkale
a4ae6dd9c4 2018-04-19 14:21:36 +08:00
Redkale
ace4042649 2018-04-18 18:30:03 +08:00
Redkale
76debd5c82 2018-04-18 17:19:48 +08:00
Redkale
8c0db6db53 2018-04-17 18:30:41 +08:00
Redkale
bc99f3f295 2018-04-17 14:24:41 +08:00
Redkale
826aaf0128 2018-04-17 13:46:30 +08:00
Redkale
754861e036 2018-04-17 11:27:34 +08:00
Redkale
b1bbc50472 2018-04-17 09:19:07 +08:00
Redkale
dcb6c6d3f8 2018-04-17 08:57:56 +08:00
Redkale
3f608b91e9 2018-04-17 08:45:31 +08:00
Redkale
9d488974a4 2018-04-16 21:53:57 +08:00
Redkale
1fa834f559 2018-04-16 21:51:21 +08:00
Redkale
812f83446e 2018-04-16 13:29:12 +08:00
Redkale
3497ab0c73 2018-04-16 08:31:24 +08:00
Redkale
78de131f83 2018-04-16 08:21:08 +08:00
Redkale
3a8ffa11fe 2018-04-15 21:07:03 +08:00
Redkale
dd62d82005 2018-04-14 13:38:13 +08:00
Redkale
7b9c71dcda 2018-04-14 13:13:13 +08:00
Redkale
4a518f1309 2018-04-14 12:52:20 +08:00
Redkale
3a0a717765 2018-04-14 12:50:13 +08:00
Redkale
60bdf4d137 2018-04-14 11:22:32 +08:00
Redkale
0ec329927a 2018-04-14 09:55:17 +08:00
Redkale
6a616b4652 2018-04-13 16:19:05 +08:00
Redkale
0bf7ccd701 2018-04-13 16:04:12 +08:00
Redkale
c924d936f3 2018-04-13 08:31:19 +08:00
Redkale
ef1c437191 HttpResponse的ContentType默认值可配置 2018-04-12 13:30:28 +08:00
Redkale
6e6d0529d6 2018-04-11 17:21:05 +08:00
Redkale
2ab179568f 2018-04-11 09:23:41 +08:00
Redkale
dab56caa98 2018-04-10 14:15:50 +08:00
Redkale
67afd13fbb 2018-04-10 11:35:11 +08:00
Redkale
3a26ddd539 2018-04-09 17:52:57 +08:00
Redkale
5197d63c70 RetLabel支持多语言版, RetLoader的load方法过期, 替换为loadMap 2018-04-09 17:28:26 +08:00
Redkale
3d136b843e 2018-04-09 14:38:40 +08:00
Redkale
388b7fbba7 2018-04-09 14:01:48 +08:00
Redkale
a833f20729 2018-04-09 10:12:44 +08:00
Redkale
d3c63bf35a 2018-04-04 14:03:55 +08:00
Redkale
5a0eff2b67 更新asm版本 2018-04-04 13:46:27 +08:00
Redkale
e64a75cfab 2018-04-03 16:16:10 +08:00
Redkale
2d31b8521d 2018-04-03 16:14:42 +08:00
Redkale
60225e3f5f 修复带空格的路径无法启动bat脚本的BUG 2018-04-03 15:19:02 +08:00
Redkale
aeb7b38474 Redkale 1.9.3 开始 2018-04-03 15:16:32 +08:00
Redkale
bfbcab4009 2018-04-03 08:29:42 +08:00
Redkale
742c352080 2018-04-02 20:53:23 +08:00
Redkale
643827354c 2018-04-02 19:29:55 +08:00
Redkale
2f7bebfc17 2018-04-02 18:48:56 +08:00
Redkale
7bf8d60ddf 2018-04-02 16:28:21 +08:00
Redkale
09c51b6b4e 2018-04-02 16:26:35 +08:00
Redkale
84f6ce58a0 2018-04-02 14:48:23 +08:00
Redkale
9e90ae5285 2018-04-02 14:08:20 +08:00
Redkale
93b1c9f0d9 2018-04-02 13:22:45 +08:00
Redkale
dab8ed8ceb 2018-03-31 11:27:11 +08:00
Redkale
f016e49111 2018-03-31 11:15:58 +08:00
Redkale
b403f22284 2018-03-31 10:46:21 +08:00
Redkale
ccb9ac93f7 ConvertFactory增加registerIgnoreAll配置 2018-03-31 10:33:57 +08:00
Redkale
72935f1ebe 2018-03-31 10:28:33 +08:00
Redkale
1f7d46219a net和WebSokcet模块增加Cryptor功能 2018-03-30 20:38:29 +08:00
Redkale
9094f76de2 Utility增加contains系列方法 2018-03-30 19:53:20 +08:00
Redkale
d67cbeb3f2 2018-03-30 17:42:18 +08:00
Redkale
90562ebd04 2018-03-30 17:25:57 +08:00
Redkale
b14e14659c 2018-03-30 08:56:00 +08:00
Redkale
84a15afc9a 2018-03-30 08:39:15 +08:00
Redkale
8c1aba5608 Transport.pollConnection的负载均衡策略改成轮询 2018-03-29 20:21:31 +08:00
Redkale
a72c689f07 2018-03-29 19:14:20 +08:00
Redkale
1d74f34575 2018-03-29 19:10:50 +08:00
Redkale
a24092d391 TransportStrategy增加offerConnection方法 2018-03-29 19:02:16 +08:00
Redkale
097ae701c1 2018-03-29 11:18:22 +08:00
Redkale
e250a593a7 完善Transport.pollConnection中连接池功能 2018-03-29 11:14:13 +08:00
Redkale
1547e6b714 Reproduce支持public field和setter、getter混合 2018-03-29 08:33:55 +08:00
Redkale
9f14224269 Reproduce增加不同字段名可以赋值的功能 2018-03-28 14:55:40 +08:00
Redkale
ecc54f9bd5 2018-03-28 09:32:21 +08:00
Redkale
521ee56d31 2018-03-28 08:59:47 +08:00
Redkale
f9da063532 2018-03-24 11:37:28 +08:00
Redkale
5070c27f6a 2018-03-24 11:34:24 +08:00
Redkale
c0664bb0a9 2018-03-24 11:28:25 +08:00
Redkale
f8c92f1ec4 2018-03-24 11:18:48 +08:00
Redkale
01930cfdc8 屏蔽sun.misc.Unsafe 2018-03-24 11:15:38 +08:00
Redkale
e76e321765 删掉过期的AsyncHandler 2018-03-21 14:14:30 +08:00
Redkale
99d2db31f7 2018-03-20 19:58:24 +08:00
Redkale
fa9015447b Redkale 1.9.2 开始 2018-03-20 19:57:19 +08:00
Redkale
735ad0908b 2018-03-17 10:44:03 +08:00
Redkale
a080a6a8cc 2018-03-16 08:45:42 +08:00
Redkale
2cbc51cfdf 2018-03-14 21:21:23 +08:00
Redkale
8631b4bdf5 Entity数据库实体类支持AtomicInteger、AtomicLong字段类型 2018-03-14 17:36:29 +08:00
Redkale
285cb86891 RetResult增加successFuture方法 2018-03-14 14:56:42 +08:00
Redkale
bf535a7161 2018-03-13 09:28:13 +08:00
Redkale
34e37471b8 2018-03-12 21:50:17 +08:00
Redkale
e223548b23 2018-03-12 21:41:36 +08:00
Redkale
3a13d242f6 2018-03-12 20:54:24 +08:00
Redkale
204e6ec99f 2018-03-12 10:04:53 +08:00
Redkale
7e348782e4 2018-03-09 19:05:37 +08:00
Redkale
a4cbe7db17 2018-03-09 09:33:42 +08:00
Redkale
f8101acb4b 2018-03-07 19:55:02 +08:00
Redkale
9ed2d59317 2018-03-07 12:50:26 +08:00
Redkale
0329ad7832 2018-03-07 12:13:06 +08:00
Redkale
53df45456f 删掉对sun.misc.Unsafe的依赖和替换过期方法Class.newInstance() 2018-03-07 11:31:11 +08:00
Redkale
93698bacff Redkale 1.9.1 开始 2018-03-07 08:30:15 +08:00
582 changed files with 73765 additions and 36830 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/target/

View File

@@ -1,12 +1,12 @@
<h1>项目介绍</h1>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 8全新的微服务框架, 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 11全新的微服务框架, 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
</p>
<strong>RedKale 有如下主要特点:</strong>
<ol>
<li>大量使用Java 8新特性接口默认值、Stream、Lambda、JDk8内置的ASM等</li>
<li>提供HTTP服务同时内置JSON功能与限时缓存功能</li>
<li>TCP层完全使用NIO.2并统一TCP与UDP的接口换</li>
<li>TCP层完全使用NIO并统一TCP与UDP的接口换</li>
<li>提供分布式与集中式部署的无缝切换</li>
<li>提供类似JPA功能包含数据缓存自动同步、分表分库与简洁的数据层操作接口</li>
<li>可以动态修改已依赖注入的资源</li>
@@ -19,8 +19,6 @@
</p>
&nbsp;&nbsp;&nbsp;编译RedKale 1.8.x版本需要在源码工程中的编译器选项中加入 <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/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>

View File

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

View File

@@ -6,7 +6,7 @@ APP_HOME=`dirname "$0"`
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/..
fi
fi
lib='.'
for jar in `ls $APP_HOME/lib/*.jar`

7
bin/command.bat Normal file
View File

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

23
bin/command.sh Normal file
View File

@@ -0,0 +1,23 @@
#!/bin/sh
export LC_ALL="zh_CN.UTF-8"
APP_HOME=`dirname "$0"`
cd "$APP_HOME"/..
APP_HOME=`pwd`
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/..
fi
lib="$APP_HOME"/lib
for jar in `ls $APP_HOME/lib/*.jar`
do
lib=$lib:$jar
done
export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME"
java -DCMD=$1 -DAPP_HOME="$APP_HOME" org.redkale.boot.Application

View File

@@ -4,6 +4,6 @@ SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
call %APP_HOME%\bin\shutdown.bat
call "%APP_HOME%\bin\shutdown.bat"
call %APP_HOME%\bin\start.bat
call "%APP_HOME%\bin\start.bat"

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
@ECHO OFF
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 -server -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

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

View File

@@ -1,21 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<application port="5050">
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
<application nodeid="10000" port="2020">
<resources>
</resources>
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
<server protocol="HTTP" port="5050">
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<response>
<defcookie domain="" path=""/>
<defcookie domain="" path="/"/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Credentials" value="true"/>
</response>
@@ -24,7 +22,7 @@
<filters autoload="true"/>
<rest path="/pipes" /> <!-- base指定的自定义HttpServlet子类必须标记@HttpUserType, 不设置base则视为没有当前用户信息设置 -->
<rest path="/pipes" />
<servlets path="/pipes" autoload="true" />

View File

@@ -1,9 +1,10 @@
handlers = java.util.logging.ConsoleHandler
# handlers = java.util.logging.FileHandler
############################################################
.level = FINER
.level = FINEST
java.level = INFO
javax.level = INFO
@@ -14,11 +15,11 @@ jdk.level = INFO
java.util.logging.FileHandler.level = FINER
#10M
java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 10000
java.util.logging.FileHandler.limit = 10M
java.util.logging.FileHandler.count = 20
java.util.logging.FileHandler.encoding = UTF-8
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.ConsoleHandler.level = FINER
java.util.logging.ConsoleHandler.level = FINEST

View File

@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence version="2.0">
<persistence-unit name="" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?autoReconnect=true&amp;characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
@@ -17,7 +15,6 @@
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="javax.persistence.jdbc.user" value="system"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
@@ -26,9 +23,8 @@
<persistence-unit name="user.write" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/user?autoReconnect=true&amp;characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
</persistence-unit>

View File

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

View File

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

View File

@@ -16,10 +16,6 @@
<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>

View File

@@ -4,16 +4,33 @@
<groupId>org.redkale</groupId>
<artifactId>redkale</artifactId>
<packaging>jar</packaging>
<name>RedkaleProject</name>
<url>http://redkale.org</url>
<description>redkale -- java framework</description>
<version>1.6.2</version>
<version>2.5.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<licenses>
<license>
<name>Apache 2</name>
<url>http://www.apache.org/licenses/</url>
<url>https://www.apache.org/licenses/</url>
<distribution>repo</distribution>
<comments>Apache License</comments>
</license>
</license>
</licenses>
<developers>
@@ -21,13 +38,13 @@
<id>Redkale</id>
<name>redkale</name>
<email>redkale@qq.com</email>
<url>http://redkale.org</url>
<url>https://redkale.org</url>
<roles>
<role>Project Manager</role>
<role>Architect</role>
</roles>
<organization>redkale</organization>
<organizationUrl>http://redkale.org</organizationUrl>
<organizationUrl>https://redkale.org</organizationUrl>
<properties>
<dept>No</dept>
</properties>
@@ -35,12 +52,6 @@
</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>
@@ -51,22 +62,24 @@
<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>
<version>3.8.0</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
@@ -74,9 +87,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<version>3.2.0</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<mainClass>org.redkale.boot.Application</mainClass>
</manifest>
@@ -98,10 +112,11 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<version>3.2.0</version>
<executions>
<execution>
<goals>
@@ -110,10 +125,11 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<version>3.2.0</version>
<executions>
<execution>
<goals>
@@ -126,7 +142,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<version>3.2.0</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>

View File

@@ -20,7 +20,8 @@
</profile>
<profile>
<id>release</id>
<id>release</id>
<!--
<build>
<plugins>
<plugin>
@@ -92,6 +93,7 @@
</plugin>
</plugins>
</build>
-->
</profile>
</profiles>
</settings>

138
pom.xml Normal file
View File

@@ -0,0 +1,138 @@
<?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>
<name>RedkaleProject</name>
<url>https://redkale.org</url>
<description>redkale -- java framework</description>
<version>2.6.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<junit.version>5.7.0</junit.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version>
</properties>
<licenses>
<license>
<name>Apache 2</name>
<url>https://www.apache.org/licenses/</url>
<distribution>repo</distribution>
<comments>Apache License</comments>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
<repository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<developers>
<developer>
<id>Redkale</id>
<name>redkale</name>
<email>redkale@qq.com</email>
<url>https://redkale.org</url>
<roles>
<role>Project Manager</role>
<role>Architect</role>
</roles>
<organization>redkale</organization>
<organizationUrl>https://redkale.org</organizationUrl>
<properties>
<dept>No</dept>
</properties>
<timezone>8</timezone>
</developer>
</developers>
<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>${maven-compiler-plugin.version}</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 需要注释掉, 否则会生成native-image配置信息
<plugin>
<groupId>org.redkale.maven.plugins</groupId>
<artifactId>redkale-maven-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<id>redkale-compile</id>
<phase>process-classes</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<mainClass>org.redkale.boot.Application</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1 @@

View File

@@ -1,63 +0,0 @@
/** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Linda DeMichiel - Java Persistence 2.1
* Linda DeMichiel - Java Persistence 2.0
*
***************************************************************************** */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Provides for the specification of generation strategies for the
* values of primary keys.
*
* <p>
* The <code>GeneratedValue</code> annotation
* may be applied to a primary key property or field of an entity or
* mapped superclass in conjunction with the {@link Id} annotation.
* The use of the <code>GeneratedValue</code> annotation is only
* required to be supported for simple primary keys. Use of the
* <code>GeneratedValue</code> annotation is not supported for derived
* primary keys.
*
* <pre>
*
* Example 1:
*
* &#064;Id
* &#064;GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
* &#064;Column(name="CUST_ID")
* public Long getId() { return id; }
*
* Example 2:
*
* &#064;Id
* &#064;GeneratedValue(strategy=TABLE, generator="CUST_GEN")
* &#064;Column(name="CUST_ID")
* Long id;
* </pre>
*
* @see Id
*
* @since Java Persistence 1.0
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface GeneratedValue {
}

View File

@@ -19,11 +19,13 @@
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
-->
<!--
address: 本地局域网的IP地址 默认值为默认网卡的ip当不使用默认值需要指定值如192.168.1.22
nodeid: int 进程的节点ID用于分布式环境一个系统中节点ID必须全局唯一使用cluster时框架会进行唯一性校验
name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线
address: 本地局域网的IP地址 默认值为默认网卡的ip当不使用默认值需要指定值如192.168.1.22
port: required 程序的管理Server的端口用于关闭或者与监管系统进行数据交互
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
-->
<application port="6560" lib="">
<application nodeid="1000" port="6560" lib="">
<!--
【节点全局唯一】
@@ -31,24 +33,73 @@
-->
<resources>
<!--
【节点全局唯一】 @since 2.3.0
全局Serivce执行的线程池 Application.workExecutor, 没配置该节点将自动创建一个。
threads 线程数为0表示不启用workExecutor只用IO线程。默认: CPU核数, 核数=1的情况下默认值为2
hash: 是否使用ThreadHashExecutor作为线程池默认值为false
-->
<executor threads="4" hash="false"/>
<!--
【节点全局唯一】
transport节点只能有一个用于配置所有Transport的池参数没配置该节点将自动创建一个。
threads 线程总数, 默认: <group>节点数*CPU核数*2
bufferCapacity: ByteBuffer的初始化大小 默认: 32K;
bufferPoolSize ByteBuffer池的大小默认: 线程总数*4
readTimeoutSecond: TCP读取超时秒数, 默认为6秒 为0表示无超时限制
writeTimeoutSecond: TCP写入超时秒数, 默认为6秒 为0表示无超时限制
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
threads 线程总数, 默认: <group>节点数*CPU核数*2
bufferCapacity: ByteBuffer的初始化大小 默认: 32K;
bufferPoolSize ByteBuffer池的大小默认: 线程总数*4
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒 为0表示无超时限制
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒 为0表示无超时限制
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
-->
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSecond="6" writeTimeoutSecond="6"/>
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSeconds="6" writeTimeoutSeconds="6"/>
<!--
【节点全局唯一】
自动扫描时排除部分包路径
value 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
-->
<excludelibs value="^.*mysql.*$;^.*kafka.*$"/>
<!--
【节点全局唯一】
第三方服务发现管理接口
value 类名必须是org.redkale.cluster.ClusterAgent的子类
waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁默认值为false
当一个Service进行服务注销后不能立刻销毁Service因为健康检测是有间隔时间差的
需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
如果使用MQ可以设置为false如果对服务健壮性要求高建议设置为true
protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
ports: 服务发现可以处理的端口, 多个端口用分号;隔开
-->
<!--
<cluster value="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071">
<property name="xxxxxx" value="XXXXXXXX"/>
</cluster>
-->
<!--
MQ管理接口配置
不同MQ节点所配置的MQ集群不能重复。
MQ跟着协议走所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的故SNCP协议下mq属性值被赋值在service/services节点上
name: 服务的名称用于监控识别多个mq节点时只能有一个name为空的节点mq.name不能重复,命名规则: 字母、数字、下划线
value 实现类名必须是org.redkale.mq.MessageAgent的子类
MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
-->
<!--
<mq name="" value="org.redkalex.mq.kafka.KafkaMessageAgent">
<servers value="127.0.0.1:9101"/>
<consumer>
<property name="xxxxxx" value="XXXXXXXX"/>
</consumer>
<producer>
<property name="xxxxxx" value="XXXXXXXX"/>
</producer>
</mq>
-->
<!--
一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
一个group节点对应一个 Transport 对象。
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol值范围UDP TCP 默认TCP
subprotocol: 子协议,预留字段。默认值为空
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol 值范围UDP TCP 默认TCP
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
-->
<group name="" protocol="TCP">
@@ -63,10 +114,10 @@
<!--
全局的数据源设置, 可以是CacheSource、DataSource JDBC的DataSource通常通过persistence.xml配置此处多用于CacheSource的配置
name: 资源名,用于依赖注入。
value类名必须是CacheSource或DataSource的子类且必须实现Service接口。如果是DataSource.class系统自动映射成DataJdbcSource.class
groups: 指定groups。
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
name: 资源名,用于依赖注入。
value 类名必须是CacheSource或DataSource的子类且必须实现Service接口。如果是DataSource.class系统自动映射成DataJdbcSource.class
groups: 指定groups。
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
-->
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
<node addr="127.0.0.1" port="7070"/>
@@ -85,13 +136,12 @@
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
load: 加载文件,多个用;隔开。
默认置入的system.property.的有:
System.setProperty("net.transport.pinginterval", "30");
System.setProperty("convert.json.tiny", "true");
System.setProperty("convert.bson.tiny", "true");
System.setProperty("convert.json.pool.size", "128");
System.setProperty("convert.bson.pool.size", "128");
System.setProperty("convert.json.writer.buffer.defsize", "4096");
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
System.setProperty("redkale.net.transport.poolmaxconns", "100");
System.setProperty("redkale.net.transport.pinginterval", "30");
System.setProperty("redkale.net.transport.checkinterval", "30");
System.setProperty("redkale.convert.tiny", "true");
System.setProperty("redkale.convert.pool.size", "128");
System.setProperty("redkale.convert.writer.buffer.defsize", "4096");
<properties>节点下也可包含非<property>节点.
<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
@@ -105,37 +155,60 @@
</resources>
<!--
protocol: required server所启动的协议Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
host: 服务所占address 默认: 0.0.0.0
port: required 服务所占端口
root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root
lib: server额外的class目录 默认为${APP_HOME}/libs/*;
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
charset: 文本编码, 默认: UTF-8
backlog: 默认10K
threads 线程数, 默认: CPU核数*8
maxconns最大连接数, 小于1表示无限制 默认: 0
maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 默认: 32K; (HTTP 2.0、WebSocket必须要16k以上)
bufferPoolSize ByteBuffer池的大小默认: 线程数*4
responsePoolSize Response池的大小默认: 线程总数*2
readTimeoutSecond: 读操作超时秒数, 默认0 表示永久不超时
writeTimeoutSecond: 操作超时秒数, 默认0 表示永久不超时
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null
protocol: required server所启动的协议Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
host: 服务所占address 默认: 0.0.0.0
port: required 服务所占端口
root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root
lib: server额外的class目录 默认为${APP_HOME}/libs/*;
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
charset: 文本编码, 默认: UTF-8
backlog: 默认10K
threads【已废弃】: 线程数, 默认: CPU核数*2最小8个【已废弃 @since 2.3.0】
maxconns 最大连接数, 小于1表示无限制 默认: 0
maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 1350B
bufferPoolSize ByteBuffer池的大小默认: 线程数*4
responsePoolSize Response池的大小默认: 1024
aliveTimeoutSeconds: KeepAlive读操作超时秒数, 默认30 0表示永久不超时; -1表示禁止KeepAlive
readTimeoutSeconds: 操作超时秒数, 默认0 表示永久不超时
writeTimeoutSeconds: 写操作超时秒数, 默认0 表示永久不超时
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null
-->
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
<!--
【节点在<server>中唯一】
builder: 创建SSLContext的实现类, 可自定义必须是org.redkale.net.SSLBuilder的子类
sslProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.OpenSSLProvider、org.bouncycastle.jce.provider.BouncyCastleProvider
jsseProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.JSSEProvider、 org.bouncycastle.jce.provider.BouncyCastleJsseProvider
protocol: TLS版本默认值: TLS
protocols: 设置setEnabledProtocols, 多个用,隔开 如: TLSv1.2,TLSv1.3
clientAuth: WANT/NEED/NONE, 默认值: NONE
ciphers: 设置setEnabledCipherSuites, 多个用,隔开 如: TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256
keystorePass: KEY密码
keystoreFile: KEY文件 .jks
keystoreType: KEY类型 默认值为JKS
keystoreAlgorithm: KEY文件的algorithm 默认值为SunX509
truststorePass: TRUST密码
truststoreFile: TRUST文件
truststoreType: TRUST类型 默认值为JKS
truststoreAlgorithm: TRUST文件的algorithm 默认值为SunX509
-->
<ssl builder=""/>
<!--
加载所有的Service服务;
在同一个进程中同一个name同一类型的Service将共用同一个实例
autoload="true" 默认值. 自动加载classpath下所有的Service类
autoload="false" 需要显著的指定Service类
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
groups: 所属组的节点,多个节点值用;隔开如果配置文件中存在多个SNCP协议的Server节点需要显式指定group属性.
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
当 protocol != SNCP 时 group只能是空或者一个group的节点值不能为多个节点值。
groups: 所属组的节点,多个节点值用;隔开如果配置文件中存在多个SNCP协议的Server节点需要显式指定group属性.
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
当 protocol != SNCP 时 group只能是空或者一个group的节点值不能为多个节点值。
特殊值"$cluster", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息
-->
<services autoload="true" includes="" excludes="">
@@ -143,6 +216,7 @@
<service value="com.xxx.XXX1Service"/>
<!--
name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
groups: 显式指定groups覆盖<services>节点的groups默认值。
ignore: 是否禁用, 默认为false。
-->
@@ -159,8 +233,8 @@
加载所有的Filter服务;
autoload="true" 默认值.
autoload="false" 需要显著的指定Filter类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<filters autoload="true" includes="" excludes="">
@@ -183,8 +257,9 @@
<!--
REST的核心配置项
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置系统会自动生成)
path: servlet的ContextPath前缀 默认为空
path: servlet的ContextPath前缀 默认为空 【注: 开启MQ时,该字段失效】
base: REST服务的BaseServlet必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
mq: 所属的MQ管理器, 存在该属性表示RestService的请求来自于消息总线 【注: 开启MQ时,path字段失效】
autoload默认值"true" 默认值. 加载当前server所能使用的Servce对象;
includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
@@ -216,46 +291,54 @@
<!--
【节点在<server>中唯一】
当Server为HTTP协议时, response节点才有效。
contenttype: plain值为调用finish时的ContentType; 默认值: text/plain; charset=utf-8
json值为调用finishJson时的ContentType; 默认值: application/json; charset=utf-8
defcookie 节点: 当response里输出的cookie没有指定domain 和path时使用该节点的默认值。
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader
options 节点: 设置了该节点auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
options 节点: 设置了该节点auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
date 节点: 设置了该节点且period有值(单位:毫秒);返回response会包含Date头信息默认为period=0
period=0表示实时获取当前时间;
period<0表示不设置date;
period>0表示定时获取时间; 设置1000表示每秒刷新Date时间
-->
<response>
<content-type plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/>
<defcookie domain="" path=""/>
<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"/>
<options auto="true" />
<date period="0" />
</response>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时render才有效. 指定输出引擎的实现类
value: 输出引擎的实现类, 必须是org.redkale.net.http.HttpRender的子类
suffixs: 引擎文件名后缀,多个用;隔开,默认值为: .htel
-->
<render value="org.redkalex.htel.HttpTemplateRender">
</render>
<render value="org.redkalex.htel.HttpTemplateRender" suffixs=".htel"/>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
webroot: web资源的根目录, 默认取server节点中的root值
servlet: 静态资源HttpServlet的实现默认使用HttpResourceServlet
index : 启始页默认值index.html
index : 启始页默认值index.html
-->
<resource-servlet webroot="root" index="index.html">
<!--
【节点在<resource-servlet>中唯一】
资源缓存的配置, 默认存在一个含默认属性的caches节点
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存 单位可以是B、K、M、G不区分大小写
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存 单位可以是B、K、M、G不区分大小写
lengthmax: 可缓存的文件大小上限, 默认: 1M超过1M的文件不会被缓存
watch: 是否监控缓存文件的变化, 默认为false不监控
watch: 是否监控缓存文件的变化, 默认为false不监控
-->
<cache limit="0M" lengthmax="1M" watch="false"/>
<!--
支持类似nginx中的rewrite 目前只支持静态资源对静态资源的跳转。
type: 匹配的类型, 目前只支持location(匹配requestURI), 默认: location
match: 匹配的正则表达式
type: 匹配的类型, 目前只支持location(匹配requestURI), 默认: location
match: 匹配的正则表达式
forward: 需跳转后的资源链接
例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html
-->
@@ -263,11 +346,11 @@
</resource-servlet>
<!--
加载所有的Servlet服务;
path: servlet的ContextPath前缀 默认为空
path: servlet的ContextPath前缀 默认为空
autoload="true" 默认值. 自动加载classpath下所有的Servlet类
autoload="false" 需要显著的指定Service类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<servlets path="/pipes" autoload="true" includes="" excludes="">
<!--

View File

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

View File

@@ -9,28 +9,21 @@
-->
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
<!--
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存 非NONE字样统一视为ALL
-->
<property name="javax.persistence.cachemode" value="ALL"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
<!--
javax.persistence.jdbc.driver在JPA的值是JDBC驱动Redkale有所不同值应该是javax.sql.DataSource的子类。
为了兼容用户习惯Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系
org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource
org.postgresql.Driver —————— org.postgresql.ds.PGConnectionPoolDataSource
com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
并且如果JDBC驱动是以上几个版本javax.persistence.jdbc.driver属性都可以省略Redkale会根据javax.persistence.jdbc.url的值来识别驱动
是否自动建表当表不存在的时候, 目前只支持mysql、postgres 默认为false
-->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.table.autoddl" value="false"/>
<!-- 多个URL用;隔开如分布式SearchSource需要配多个URL -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<!-- 最大连接数默认值CPU数*16 -->
<property name="javax.persistence.connections.limit" value="32"/>
<!-- 最大连接数默认值CPU数 -->
<property name="javax.persistence.connections.limit" value="12"/>
<!-- 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句 -->
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
@@ -38,7 +31,7 @@
<!-- 复制表结构的SQL模板Redkale内置了MySQL的语句 -->
<property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}"/>
</properties>
</persistence-unit>
@@ -47,7 +40,6 @@
<properties>
<!-- 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.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
</properties>

View File

@@ -23,11 +23,17 @@ import java.lang.annotation.Target;
/**
* 值越大优先级越高
*
*
* @since Common Annotations 1.2
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Priority {
/**
* 优先级值
*
* @return int
*/
int value();
}

View File

@@ -16,17 +16,68 @@ import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {
/**
* AuthenticationType
*/
@Deprecated
public enum AuthenticationType {
/**
* @deprecated
*/
CONTAINER,
/**
* @deprecated
*/
APPLICATION
}
/**
* 资源名称
*
* @return String
*/
public String name() default "";
/**
* 依赖注入的类型
*
* @return Class
*/
public Class<?> type() default Object.class;
/**
*
* @return AuthenticationType
*/
@Deprecated
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
/**
*
* @return boolean
*/
@Deprecated
public boolean shareable() default true;
/**
*
* @return String
*/
@Deprecated
public String description() default "";
/**
*
* @return String
*/
@Deprecated
public String mappedName() default "";
/**
*
* @return String
*/
@Deprecated
public String lookup() default "";
}

View File

@@ -51,4 +51,12 @@ public @interface Cacheable {
* @return int
*/
int interval() default 0;
/**
* DataSource是否直接返回对象的真实引用 而不是copy一份
*
* @return boolean
*/
boolean direct() default false;
}

View File

@@ -81,12 +81,19 @@ public @interface Column {
boolean unique() default false;
/**
* (Optional) Whether the database column is nullable.
* (Optional) Whether the database column is required.
*
* @return boolean
*/
boolean nullable() default true;
/**
* for OpenAPI Specification 3
*
* @return String
*/
String example() default "";
/**
* (Optional) Whether the column is included in SQL INSERT
* statements generated by the persistence provider.
@@ -109,11 +116,13 @@ public @interface Column {
*
* @return String
*/
@Deprecated
String table() default "";
/**
* (Optional) The column length. (Applies only if a
* string-valued column is used.)
* if type==String and length == 65535 then sqltype is text
*
* @return int
*/

View File

@@ -15,9 +15,7 @@
******************************************************************************/
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -27,6 +25,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*
* @since Java Persistence 1.0
*/
@Inherited
@Documented
@Target(TYPE)
@Retention(RUNTIME)

View File

@@ -45,7 +45,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </pre>
*
* @see Column
* @see GeneratedValue
* see GeneratedValue
*
* @since Java Persistence 1.0
*/

View File

@@ -82,6 +82,11 @@ public @interface Table {
*/
Index[] indexes() default {};
/**
* comment
*
* @return String
*/
String comment() default "";
}

View File

@@ -4,26 +4,29 @@
*
* @author zhangjx
*
module org.redkale {
*/
module redkale {
requires java.base;
requires java.logging;
requires java.xml;
requires java.logging;
requires java.net.http;
requires java.sql;
requires java.sql.rowset;
requires jdk.unsupported; //sun.misc.Unsafe
exports javax.annotation;
exports javax.persistence;
exports org.redkale.asm;
exports org.redkale.boot;
exports org.redkale.boot.watch;
exports org.redkale.cluster;
exports org.redkale.convert;
exports org.redkale.convert.bson;
exports org.redkale.convert.ext;
exports org.redkale.convert.json;
exports org.redkale.mq;
exports org.redkale.net;
exports org.redkale.net.client;
exports org.redkale.net.http;
exports org.redkale.net.sncp;
exports org.redkale.service;
@@ -31,5 +34,11 @@ module org.redkale {
exports org.redkale.util;
exports org.redkale.watch;
uses org.redkale.mq.MessageAgent;
uses org.redkale.cluster.ClusterAgent;
uses org.redkale.convert.ConvertProvider;
uses org.redkale.source.CacheSourceProvider;
uses org.redkale.source.DataSourceProvider;
uses org.redkale.util.ResourceInjectLoader;
}
*/

View File

@@ -60,8 +60,8 @@ package org.redkale.asm;
/**
* A visitor to visit a Java annotation. The methods of this class must be
* called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
* <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
* called in the following order: ( &#60;tt&#62;visit&#60;/tt&#62; | &#60;tt&#62;visitEnum&#60;/tt&#62; |
* &#60;tt&#62;visitAnnotation&#60;/tt&#62; | &#60;tt&#62;visitArray&#60;/tt&#62; )* &#60;tt&#62;visitEnd&#60;/tt&#62;.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
@@ -70,7 +70,7 @@ public abstract class AnnotationVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -85,7 +85,7 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public AnnotationVisitor(final int api) {
this(api, null);
@@ -96,15 +96,12 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param av
* the annotation visitor to which this visitor must delegate
* method calls. May be null.
*/
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.av = av;
}
@@ -118,7 +115,7 @@ public abstract class AnnotationVisitor {
* the actual value, whose type must be {@link Byte},
* {@link Boolean}, {@link Character}, {@link Short},
* {@link Integer} , {@link Long}, {@link Float}, {@link Double},
* {@link String} or {@link Type} or OBJECT or ARRAY sort. This
* {@link String} or {@link Type} of OBJECT or ARRAY sort. This
* value can also be an array of byte, boolean, short, char, int,
* long, float or double values (this is equivalent to using
* {@link #visitArray visitArray} and visiting each array element
@@ -154,7 +151,7 @@ public abstract class AnnotationVisitor {
* @param desc
* the class descriptor of the nested annotation class.
* @return a visitor to visit the actual nested annotation value, or
* <tt>null</tt> if this visitor is not interested in visiting this
* &#60;tt&#62;null&#60;/tt&#62; if this visitor is not interested in visiting this
* nested annotation. <i>The nested annotation value must be fully
* visited before calling other methods on this annotation
* visitor</i>.
@@ -175,7 +172,7 @@ public abstract class AnnotationVisitor {
* @param name
* the value name.
* @return a visitor to visit the actual array value elements, or
* <tt>null</tt> if this visitor is not interested in visiting these
* &#60;tt&#62;null&#60;/tt&#62; if this visitor is not interested in visiting these
* values. The 'name' parameters passed to the methods of this
* visitor are ignored. <i>All the array values must be visited
* before calling other methods on this annotation visitor</i>.

View File

@@ -77,7 +77,7 @@ final class AnnotationWriter extends AnnotationVisitor {
private int size;
/**
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
* &#60;tt&#62;true&#60;tt&#62; if values are named, &#60;tt&#62;false&#60;/tt&#62; otherwise. Annotation
* writers used for annotation default and annotation arrays use unnamed
* values.
*/
@@ -122,18 +122,18 @@ final class AnnotationWriter extends AnnotationVisitor {
* @param cw
* the class writer to which this annotation must be added.
* @param named
* <tt>true<tt> if values are named, <tt>false</tt> otherwise.
* &#60;tt&#62;true&#60;tt&#62; if values are named, &#60;tt&#62;false&#60;/tt&#62; otherwise.
* @param bv
* where the annotation values must be stored.
* @param parent
* where the number of annotation values must be stored.
* @param offset
* where in <tt>parent</tt> the number of annotation values must
* where in &#60;tt&#62;parent&#60;/tt&#62; the number of annotation values must
* be stored.
*/
AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset) {
super(Opcodes.ASM5);
super(Opcodes.ASM6);
this.cw = cw;
this.named = named;
this.bv = bv;
@@ -354,7 +354,7 @@ final class AnnotationWriter extends AnnotationVisitor {
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param out
* where the type reference and type path must be put.
*/

View File

@@ -58,6 +58,8 @@
*/
package org.redkale.asm;
import java.util.Arrays;
/**
* A non standard class, field, method or code attribute.
*
@@ -77,7 +79,7 @@ public class Attribute {
byte[] value;
/**
* The next attribute in this attribute list. May be <tt>null</tt>.
* The next attribute in this attribute list. May be &#60;tt&#62;null&#60;/tt&#62;.
*/
Attribute next;
@@ -92,19 +94,19 @@ public class Attribute {
}
/**
* Returns <tt>true</tt> if this type of attribute is unknown. The default
* implementation of this method always returns <tt>true</tt>.
* Returns &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is unknown. The default
* implementation of this method always returns &#60;tt&#62;true&#60;/tt&#62;.
*
* @return <tt>true</tt> if this type of attribute is unknown.
* @return &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is unknown.
*/
public boolean isUnknown() {
return true;
}
/**
* Returns <tt>true</tt> if this type of attribute is a code attribute.
* Returns &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is a code attribute.
*
* @return <tt>true</tt> if this type of attribute is a code attribute.
* @return &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is a code attribute.
*/
public boolean isCodeAttribute() {
return false;
@@ -113,7 +115,7 @@ public class Attribute {
/**
* Returns the labels corresponding to this attribute.
*
* @return the labels corresponding to this attribute, or <tt>null</tt> if
* @return the labels corresponding to this attribute, or &#60;tt&#62;null&#60;/tt&#62; if
* this attribute is not a code attribute that contains labels.
*/
protected Label[] getLabels() {
@@ -123,7 +125,7 @@ public class Attribute {
/**
* Reads a {@link #type type} attribute. This method must return a
* <i>new</i> {@link Attribute} object, of type {@link #type type},
* corresponding to the <tt>len</tt> bytes starting at the given offset, in
* corresponding to the &#60;tt&#62;len&#60;/tt&#62; bytes starting at the given offset, in
* the given class reader.
*
* @param cr
@@ -146,7 +148,7 @@ public class Attribute {
* containing the type and the length of the attribute, are not
* taken into account here.
* @param labels
* the labels of the method's code, or <tt>null</tt> if the
* the labels of the method's code, or &#60;tt&#62;null&#60;/tt&#62; if the
* attribute to be read is not a code attribute.
* @return a <i>new</i> {@link Attribute} object corresponding to the given
* bytes.
@@ -169,11 +171,11 @@ public class Attribute {
* class the items that corresponds to this attribute.
* @param code
* the bytecode of the method corresponding to this code
* attribute, or <tt>null</tt> if this attribute is not a code
* attribute, or &#60;tt&#62;null&#60;/tt&#62; if this attribute is not a code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to this
* code attribute, or <tt>null</tt> if this attribute is not a
* code attribute, or &#60;tt&#62;null&#60;/tt&#62; if this attribute is not a
* code attribute.
* @param maxStack
* the maximum stack size of the method corresponding to this
@@ -216,11 +218,11 @@ public class Attribute {
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes, or &#60;tt&#62;null&#60;/tt&#62; if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* these code attributes, or &#60;tt&#62;null&#60;/tt&#62; if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
@@ -254,11 +256,11 @@ public class Attribute {
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes, or &#60;tt&#62;null&#60;/tt&#62; if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* these code attributes, or &#60;tt&#62;null&#60;/tt&#62; if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
@@ -281,4 +283,82 @@ public class Attribute {
attr = attr.next;
}
}
//The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely removed.
//see also changes in ClassReader.accept.
/**
*
*/
public static class NestMembers extends Attribute {
/**
*
*/
public NestMembers() {
super("NestMembers");
}
byte[] bytes;
String[] classes;
@Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
int offset = off;
NestMembers a = new NestMembers();
int size = cr.readShort(off);
a.classes = new String[size];
off += 2;
for (int i = 0; i < size ; i++) {
a.classes[i] = cr.readClass(off, buf);
off += 2;
}
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
return a;
}
@Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
ByteVector v = new ByteVector(bytes.length);
v.putShort(classes.length);
for (String s : classes) {
v.putShort(cw.newClass(s));
}
return v;
}
}
/**
*
*/
public static class NestHost extends Attribute {
byte[] bytes;
String clazz;
/**
*
*/
public NestHost() {
super("NestHost");
}
@Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
int offset = off;
NestHost a = new NestHost();
a.clazz = cr.readClass(off, buf);
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
return a;
}
@Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
ByteVector v = new ByteVector(bytes.length);
v.putShort(cw.newClass(clazz));
return v;
}
}
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {
new NestMembers(),
new NestHost()
};
}

View File

@@ -332,7 +332,7 @@ public class ByteVector {
* automatically enlarged if necessary.
*
* @param b
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
* an array of bytes. May be &#60;tt&#62;null&#60;/tt&#62; to put &#60;tt&#62;len&#60;/tt&#62;
* null bytes into this byte vector.
* @param off
* index of the fist byte of b that must be copied.

View File

@@ -72,31 +72,6 @@ import java.io.InputStream;
*/
public class ClassReader {
/**
* True to enable signatures support.
*/
static final boolean SIGNATURES = true;
/**
* True to enable annotations support.
*/
static final boolean ANNOTATIONS = true;
/**
* True to enable stack map frames support.
*/
static final boolean FRAMES = true;
/**
* True to enable bytecode writing support.
*/
static final boolean WRITER = true;
/**
* True to enable JSR_W and GOTO_W support.
*/
static final boolean RESIZE = true;
/**
* Flag to skip method code. If this class is set <code>CODE</code>
* attribute won't be visited. This can be used, for example, to retrieve
@@ -133,6 +108,21 @@ public class ClassReader {
*/
public static final int EXPAND_FRAMES = 8;
/**
* Flag to expand the ASM pseudo instructions into an equivalent sequence of
* standard bytecode instructions. When resolving a forward jump it may
* happen that the signed 2 bytes offset reserved for it is not sufficient
* to store the bytecode offset. In this case the jump instruction is
* replaced with a temporary ASM pseudo instruction using an unsigned 2
* bytes offset (see Label#resolve). This internal flag is used to re-read
* classes containing such instructions, in order to replace them with
* standard instructions. In addition, when this flag is used, GOTO_W and
* JSR_W are <i>not</i> converted into GOTO and JSR, to make sure that
* infinite loops where a GOTO_W is replaced with a GOTO in ClassReader and
* converted back to a GOTO_W in ClassWriter cannot occur.
*/
static final int EXPAND_ASM_INSNS = 256;
/**
* The class to be parsed. <i>The content of this array must not be
* modified. This field is intended for {@link Attribute} sub classes, and
@@ -195,9 +185,9 @@ public class ClassReader {
public ClassReader(final byte[] b, final int off, final int len) {
this.b = b;
// checks the class version
if (readShort(off + 6) > Opcodes.V1_9) {
throw new IllegalArgumentException();
}
//if (readShort(off + 6) > Opcodes.V11) {
// throw new IllegalArgumentException();
//}
// parses the constant pool
items = new int[readUnsignedShort(off + 8)];
int n = items.length;
@@ -215,6 +205,10 @@ public class ClassReader {
case ClassWriter.FLOAT:
case ClassWriter.NAME_TYPE:
case ClassWriter.INDY:
// @@@ ClassWriter.CONDY
// Enables MethodHandles.lookup().defineClass to function correctly
// when it reads the class name
case 17:
size = 5;
break;
case ClassWriter.LONG:
@@ -234,6 +228,8 @@ public class ClassReader {
// case ClassWriter.CLASS:
// case ClassWriter.STR:
// case ClassWriter.MTYPE
// case ClassWriter.PACKAGE:
// case ClassWriter.MODULE:
default:
size = 3;
break;
@@ -275,7 +271,7 @@ public class ClassReader {
* {@link Type#getInternalName() getInternalName}). For interfaces, the
* super class is {@link Object}.
*
* @return the internal name of super class, or <tt>null</tt> for
* @return the internal name of super class, or &#60;tt&#62;null&#60;/tt&#62; for
* {@link Object} class.
*
* @see ClassVisitor#visit(int, int, String, String, String, String[])
@@ -289,7 +285,7 @@ public class ClassReader {
* {@link Type#getInternalName() getInternalName}).
*
* @return the array of internal names for all implemented interfaces or
* <tt>null</tt>.
* &#60;tt&#62;null&#60;/tt&#62;.
*
* @see ClassVisitor#visit(int, int, String, String, String, String[])
*/
@@ -377,7 +373,9 @@ public class ClassReader {
break;
// case ClassWriter.STR:
// case ClassWriter.CLASS:
// case ClassWriter.MTYPE
// case ClassWriter.MTYPE:
// case ClassWriter.MODULE:
// case ClassWriter.PACKAGE:
default:
item.set(tag, readUTF8(index, buf), null, null);
break;
@@ -532,7 +530,7 @@ public class ClassReader {
* , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
*/
public void accept(final ClassVisitor classVisitor, final int flags) {
accept(classVisitor, new Attribute[0], flags);
accept(classVisitor, Attribute.DEFAULT_ATTRIBUTE_PROTOS, flags);
}
/**
@@ -584,11 +582,14 @@ public class ClassReader {
String enclosingOwner = null;
String enclosingName = null;
String enclosingDesc = null;
String moduleMainClass = null;
int anns = 0;
int ianns = 0;
int tanns = 0;
int itanns = 0;
int innerClasses = 0;
int module = 0;
int packages = 0;
Attribute attributes = null;
u = getAttributes();
@@ -607,13 +608,11 @@ public class ClassReader {
enclosingName = readUTF8(items[item], c);
enclosingDesc = readUTF8(items[item] + 2, c);
}
} else if (SIGNATURES && "Signature".equals(attrName)) {
} else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8;
} else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED;
@@ -623,12 +622,16 @@ public class ClassReader {
} else if ("SourceDebugExtension".equals(attrName)) {
int len = readInt(u + 4);
sourceDebug = readUTF(u + 8, len, new char[len]);
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8;
} else if ("Module".equals(attrName)) {
module = u + 8;
} else if ("ModuleMainClass".equals(attrName)) {
moduleMainClass = readClass(u + 8, c);
} else if ("ModulePackages".equals(attrName)) {
packages = u + 10;
} else if ("BootstrapMethods".equals(attrName)) {
int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
@@ -657,6 +660,12 @@ public class ClassReader {
classVisitor.visitSource(sourceFile, sourceDebug);
}
// visits the module info and associated attributes
if (module != 0) {
readModule(classVisitor, context, module,
moduleMainClass, packages);
}
// visits the outer class
if (enclosingOwner != null) {
classVisitor.visitOuterClass(enclosingOwner, enclosingName,
@@ -664,19 +673,19 @@ public class ClassReader {
}
// visits the class annotations and type annotations
if (ANNOTATIONS && anns != 0) {
if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
classVisitor.visitAnnotation(readUTF8(v, c), true));
}
}
if (ANNOTATIONS && ianns != 0) {
if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
classVisitor.visitAnnotation(readUTF8(v, c), false));
}
}
if (ANNOTATIONS && tanns != 0) {
if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -684,7 +693,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true));
}
}
if (ANNOTATIONS && itanns != 0) {
if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -726,6 +735,120 @@ public class ClassReader {
classVisitor.visitEnd();
}
/**
* Reads the module attribute and visit it.
*
* @param classVisitor
* the current class visitor
* @param context
* information about the class being parsed.
* @param u
* start offset of the module attribute in the class file.
* @param mainClass
* name of the main class of a module or null.
* @param packages
* start offset of the concealed package attribute.
*/
private void readModule(final ClassVisitor classVisitor,
final Context context, int u,
final String mainClass, int packages) {
char[] buffer = context.buffer;
// reads module name, flags and version
String name = readModule(u, buffer);
int flags = readUnsignedShort(u + 2);
String version = readUTF8(u + 4, buffer);
u += 6;
ModuleVisitor mv = classVisitor.visitModule(name, flags, version);
if (mv == null) {
return;
}
// module attributes (main class, packages)
if (mainClass != null) {
mv.visitMainClass(mainClass);
}
if (packages != 0) {
for (int i = readUnsignedShort(packages - 2); i > 0; --i) {
String packaze = readPackage(packages, buffer);
mv.visitPackage(packaze);
packages += 2;
}
}
// reads requires
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String module = readModule(u, buffer);
int access = readUnsignedShort(u + 2);
String requireVersion = readUTF8(u + 4, buffer);
mv.visitRequire(module, access, requireVersion);
u += 6;
}
// reads exports
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String export = readPackage(u, buffer);
int access = readUnsignedShort(u + 2);
int exportToCount = readUnsignedShort(u + 4);
u += 6;
String[] tos = null;
if (exportToCount != 0) {
tos = new String[exportToCount];
for (int j = 0; j < tos.length; ++j) {
tos[j] = readModule(u, buffer);
u += 2;
}
}
mv.visitExport(export, access, tos);
}
// reads opens
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String open = readPackage(u, buffer);
int access = readUnsignedShort(u + 2);
int openToCount = readUnsignedShort(u + 4);
u += 6;
String[] tos = null;
if (openToCount != 0) {
tos = new String[openToCount];
for (int j = 0; j < tos.length; ++j) {
tos[j] = readModule(u, buffer);
u += 2;
}
}
mv.visitOpen(open, access, tos);
}
// read uses
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
mv.visitUse(readClass(u, buffer));
u += 2;
}
// read provides
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String service = readClass(u, buffer);
int provideWithCount = readUnsignedShort(u + 2);
u += 4;
String[] withs = new String[provideWithCount];
for (int j = 0; j < withs.length; ++j) {
withs[j] = readClass(u, buffer);
u += 2;
}
mv.visitProvide(service, withs);
}
mv.visitEnd();
}
/**
* Reads a field and makes the given visitor visit it.
*
@@ -762,24 +885,20 @@ public class ClassReader {
if ("ConstantValue".equals(attrName)) {
int item = readUnsignedShort(u + 8);
value = item == 0 ? null : readConst(item, c);
} else if (SIGNATURES && "Signature".equals(attrName)) {
} else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED;
} else if ("Synthetic".equals(attrName)) {
access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8;
} else {
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
@@ -801,19 +920,19 @@ public class ClassReader {
}
// visits the field annotations and type annotations
if (ANNOTATIONS && anns != 0) {
if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
fv.visitAnnotation(readUTF8(v, c), true));
}
}
if (ANNOTATIONS && ianns != 0) {
if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
fv.visitAnnotation(readUTF8(v, c), false));
}
}
if (ANNOTATIONS && tanns != 0) {
if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -821,7 +940,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true));
}
}
if (ANNOTATIONS && itanns != 0) {
if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -895,32 +1014,26 @@ public class ClassReader {
exceptions[j] = readClass(exception, c);
exception += 2;
}
} else if (SIGNATURES && "Signature".equals(attrName)) {
} else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) {
context.access |= Opcodes.ACC_DEPRECATED;
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8;
} else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) {
} else if ("AnnotationDefault".equals(attrName)) {
dann = u + 8;
} else if ("Synthetic".equals(attrName)) {
context.access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleParameterAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) {
mpanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) {
impanns = u + 8;
} else if ("MethodParameters".equals(attrName)) {
methodParameters = u + 8;
@@ -953,7 +1066,7 @@ public class ClassReader {
* access, name and descriptor can have been changed, this is not
* important since they are not copied as is from the reader).
*/
if (WRITER && mv instanceof MethodWriter) {
if (mv instanceof MethodWriter) {
MethodWriter mw = (MethodWriter) mv;
if (mw.cw.cr == this && signature == mw.signature) {
boolean sameExceptions = false;
@@ -990,26 +1103,26 @@ public class ClassReader {
}
// visits the method annotations
if (ANNOTATIONS && dann != 0) {
if (dann != 0) {
AnnotationVisitor dv = mv.visitAnnotationDefault();
readAnnotationValue(dann, c, null, dv);
if (dv != null) {
dv.visitEnd();
}
}
if (ANNOTATIONS && anns != 0) {
if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
mv.visitAnnotation(readUTF8(v, c), true));
}
}
if (ANNOTATIONS && ianns != 0) {
if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
mv.visitAnnotation(readUTF8(v, c), false));
}
}
if (ANNOTATIONS && tanns != 0) {
if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -1017,7 +1130,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true));
}
}
if (ANNOTATIONS && itanns != 0) {
if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -1025,10 +1138,10 @@ public class ClassReader {
context.typePath, readUTF8(v, c), false));
}
}
if (ANNOTATIONS && mpanns != 0) {
if (mpanns != 0) {
readParameterAnnotations(mv, context, mpanns, true);
}
if (ANNOTATIONS && impanns != 0) {
if (impanns != 0) {
readParameterAnnotations(mv, context, impanns, false);
}
@@ -1075,7 +1188,7 @@ public class ClassReader {
int codeStart = u;
int codeEnd = u + codeLength;
Label[] labels = context.labels = new Label[codeLength + 2];
readLabel(codeLength + 1, labels);
createLabel(codeLength + 1, labels);
while (u < codeEnd) {
int offset = u - codeStart;
int opcode = b[u] & 0xFF;
@@ -1085,11 +1198,16 @@ public class ClassReader {
u += 1;
break;
case ClassWriter.LABEL_INSN:
readLabel(offset + readShort(u + 1), labels);
createLabel(offset + readShort(u + 1), labels);
u += 3;
break;
case ClassWriter.ASM_LABEL_INSN:
createLabel(offset + readUnsignedShort(u + 1), labels);
u += 3;
break;
case ClassWriter.LABELW_INSN:
readLabel(offset + readInt(u + 1), labels);
case ClassWriter.ASM_LABELW_INSN:
createLabel(offset + readInt(u + 1), labels);
u += 5;
break;
case ClassWriter.WIDE_INSN:
@@ -1104,9 +1222,9 @@ public class ClassReader {
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
readLabel(offset + readInt(u), labels);
createLabel(offset + readInt(u), labels);
for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
readLabel(offset + readInt(u + 12), labels);
createLabel(offset + readInt(u + 12), labels);
u += 4;
}
u += 12;
@@ -1115,9 +1233,9 @@ public class ClassReader {
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
readLabel(offset + readInt(u), labels);
createLabel(offset + readInt(u), labels);
for (int i = readInt(u + 4); i > 0; --i) {
readLabel(offset + readInt(u + 12), labels);
createLabel(offset + readInt(u + 12), labels);
u += 8;
}
u += 8;
@@ -1147,9 +1265,9 @@ public class ClassReader {
// reads the try catch entries to find the labels, and also visits them
for (int i = readUnsignedShort(u); i > 0; --i) {
Label start = readLabel(readUnsignedShort(u + 2), labels);
Label end = readLabel(readUnsignedShort(u + 4), labels);
Label handler = readLabel(readUnsignedShort(u + 6), labels);
Label start = createLabel(readUnsignedShort(u + 2), labels);
Label end = createLabel(readUnsignedShort(u + 4), labels);
Label handler = createLabel(readUnsignedShort(u + 6), labels);
String type = readUTF8(items[readUnsignedShort(u + 8)], c);
mv.visitTryCatchBlock(start, end, handler, type);
u += 8;
@@ -1180,13 +1298,9 @@ public class ClassReader {
varTable = u + 8;
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
createDebugLabel(label, labels);
label += readUnsignedShort(v + 12);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
createDebugLabel(label, labels);
v += 10;
}
}
@@ -1196,9 +1310,7 @@ public class ClassReader {
if ((context.flags & SKIP_DEBUG) == 0) {
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
createDebugLabel(label, labels);
Label l = labels[label];
while (l.line > 0) {
if (l.next == null) {
@@ -1210,17 +1322,15 @@ public class ClassReader {
v += 4;
}
}
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = readTypeAnnotations(mv, context, u + 8, true);
ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
: readUnsignedShort(tanns[0] + 1);
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = readTypeAnnotations(mv, context, u + 8, false);
nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
: readUnsignedShort(itanns[0] + 1);
} else if (FRAMES && "StackMapTable".equals(attrName)) {
} else if ("StackMapTable".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
stackMap = u + 10;
stackMapSize = readInt(u + 4);
@@ -1244,7 +1354,7 @@ public class ClassReader {
* this by parsing the stack map table without a full decoding
* (see below).
*/
} else if (FRAMES && "StackMap".equals(attrName)) {
} else if ("StackMap".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
zip = false;
stackMap = u + 10;
@@ -1273,7 +1383,7 @@ public class ClassReader {
u += 2;
// generates the first (implicit) stack map frame
if (FRAMES && stackMap != 0) {
if (stackMap != 0) {
/*
* for the first explicit frame the offset is not offset_delta + 1
* but only offset_delta; setting the implicit frame offset to -1
@@ -1306,14 +1416,31 @@ public class ClassReader {
int v = readUnsignedShort(i + 1);
if (v >= 0 && v < codeLength) {
if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
readLabel(v, labels);
createLabel(v, labels);
}
}
}
}
}
if ((context.flags & EXPAND_ASM_INSNS) != 0
&& (context.flags & EXPAND_FRAMES) != 0) {
// Expanding the ASM pseudo instructions can introduce F_INSERT
// frames, even if the method does not currently have any frame.
// Also these inserted frames must be computed by simulating the
// effect of the bytecode instructions one by one, starting from the
// first one and the last existing frame (or the implicit first
// one). Finally, due to the way MethodWriter computes this (with
// the compute = INSERTED_FRAMES option), MethodWriter needs to know
// maxLocals before the first instruction is visited. For all these
// reasons we always visit the implicit first frame in this case
// (passing only maxLocals - the rest can be and is computed in
// MethodWriter).
mv.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
}
// visits the instructions
int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0;
boolean insertFrame = false;
u = codeStart;
while (u < codeEnd) {
int offset = u - codeStart;
@@ -1334,7 +1461,7 @@ public class ClassReader {
}
// visits the frame for this offset, if any
while (FRAMES && frame != null
while (frame != null
&& (frame.offset == offset || frame.offset == -1)) {
// if there is a frame for this offset, makes the visitor visit
// it, and reads the next frame if there is one.
@@ -1346,6 +1473,9 @@ public class ClassReader {
mv.visitFrame(frame.mode, frame.localDiff, frame.local,
frame.stackCount, frame.stack);
}
// if there is already a frame for this offset, there is no
// need to insert a new one.
insertFrame = false;
}
if (frameCount > 0) {
stackMap = readFrame(stackMap, zip, unzip, frame);
@@ -1354,6 +1484,13 @@ public class ClassReader {
frame = null;
}
}
// inserts a frame for this offset, if requested by setting
// insertFrame to true during the previous iteration. The actual
// frame content will be computed in MethodWriter.
if (insertFrame) {
mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null);
insertFrame = false;
}
// visits the instruction at this offset
int opcode = b[u] & 0xFF;
@@ -1378,9 +1515,47 @@ public class ClassReader {
u += 3;
break;
case ClassWriter.LABELW_INSN:
mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]);
mv.visitJumpInsn(opcode + opcodeDelta, labels[offset
+ readInt(u + 1)]);
u += 5;
break;
case ClassWriter.ASM_LABEL_INSN: {
// changes temporary opcodes 202 to 217 (inclusive), 218
// and 219 to IFEQ ... JSR (inclusive), IFNULL and
// IFNONNULL
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
Label target = labels[offset + readUnsignedShort(u + 1)];
// replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
// <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is
// the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
// and where <L> designates the instruction just after
// the GOTO_W.
if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
mv.visitJumpInsn(opcode + 33, target);
} else {
opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1
: opcode ^ 1;
Label endif = createLabel(offset + 3, labels);
mv.visitJumpInsn(opcode, endif);
mv.visitJumpInsn(200, target); // GOTO_W
// endif designates the instruction just after GOTO_W,
// and is visited as part of the next instruction. Since
// it is a jump target, we need to insert a frame here.
insertFrame = true;
}
u += 3;
break;
}
case ClassWriter.ASM_LABELW_INSN: {
// replaces the pseudo GOTO_W instruction with a real one.
mv.visitJumpInsn(200, labels[offset + readInt(u + 1)]);
// The instruction just after is a jump target (because pseudo
// GOTO_W are used in patterns IFNOTxxx <L> GOTO_W <l> L:...,
// see MethodWriter), so we need to insert a frame here.
insertFrame = true;
u += 5;
break;
}
case ClassWriter.WIDE_INSN:
opcode = b[u + 1] & 0xFF;
if (opcode == Opcodes.IINC) {
@@ -1636,8 +1811,8 @@ public class ClassReader {
for (int j = readUnsignedShort(u + 1); j > 0; --j) {
int start = readUnsignedShort(u + 3);
int length = readUnsignedShort(u + 5);
readLabel(start, context.labels);
readLabel(start + length, context.labels);
createLabel(start, context.labels);
createLabel(start + length, context.labels);
u += 6;
}
u += 3;
@@ -1716,8 +1891,8 @@ public class ClassReader {
for (int i = 0; i < n; ++i) {
int start = readUnsignedShort(u);
int length = readUnsignedShort(u + 2);
context.start[i] = readLabel(start, context.labels);
context.end[i] = readLabel(start + length, context.labels);
context.start[i] = createLabel(start, context.labels);
context.end[i] = createLabel(start + length, context.labels);
context.index[i] = readUnsignedShort(u + 4);
u += 6;
}
@@ -1761,7 +1936,7 @@ public class ClassReader {
* @param v
* start offset in {@link #b b} of the annotations to be read.
* @param visible
* <tt>true</tt> if the annotations to be read are visible at
* &#60;tt&#62;true&#60;/tt&#62; if the annotations to be read are visible at
* runtime.
*/
private void readParameterAnnotations(final MethodVisitor mv,
@@ -2137,7 +2312,7 @@ public class ClassReader {
}
}
frame.offset += delta + 1;
readLabel(frame.offset, labels);
createLabel(frame.offset, labels);
return stackMap;
}
@@ -2190,7 +2365,7 @@ public class ClassReader {
v += 2;
break;
default: // Uninitialized
frame[index] = readLabel(readUnsignedShort(v), labels);
frame[index] = createLabel(readUnsignedShort(v), labels);
v += 2;
}
return v;
@@ -2216,6 +2391,39 @@ public class ClassReader {
return labels[offset];
}
/**
* Creates a label without the Label.DEBUG flag set, for the given offset.
* The label is created with a call to {@link #readLabel} and its
* Label.DEBUG flag is cleared.
*
* @param offset
* a bytecode offset in a method.
* @param labels
* the already created labels, indexed by their offset.
* @return a Label without the Label.DEBUG flag set.
*/
private Label createLabel(int offset, Label[] labels) {
Label label = readLabel(offset, labels);
label.status &= ~Label.DEBUG;
return label;
}
/**
* Creates a label with the Label.DEBUG flag set, if there is no already
* existing label for the given offset (otherwise does nothing). The label
* is created with a call to {@link #readLabel}.
*
* @param offset
* a bytecode offset in a method.
* @param labels
* the already created labels, indexed by their offset.
*/
private void createDebugLabel(int offset, Label[] labels) {
if (labels[offset] == null) {
readLabel(offset, labels).status |= Label.DEBUG;
}
}
/**
* Returns the start index of the attribute_info structure of this class.
*
@@ -2270,9 +2478,9 @@ public class ClassReader {
* and the length of the attribute, are not taken into account
* here.
* @param labels
* the labels of the method's code, or <tt>null</tt> if the
* the labels of the method's code, or &#60;tt&#62;null&#60;/tt&#62; if the
* attribute to be read is not a code attribute.
* @return the attribute that has been read, or <tt>null</tt> to skip this
* @return the attribute that has been read, or &#60;tt&#62;null&#60;/tt&#62; to skip this
* attribute.
*/
private Attribute readAttribute(final Attribute[] attrs, final String type,
@@ -2470,6 +2678,20 @@ public class ClassReader {
return new String(buf, 0, strLen);
}
/**
* Read a stringish constant item (CONSTANT_Class, CONSTANT_String,
* CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package
* @param index
* @param buf
* @return
*/
private String readStringish(final int index, final char[] buf) {
// computes the start index of the item in b
// and reads the CONSTANT_Utf8 item designated by
// the first two bytes of this item
return readUTF8(items[readUnsignedShort(index)], buf);
}
/**
* Reads a class constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
@@ -2484,44 +2706,41 @@ public class ClassReader {
* @return the String corresponding to the specified class item.
*/
public String readClass(final int index, final char[] buf) {
// computes the start index of the CONSTANT_Class item in b
// and reads the CONSTANT_Utf8 item designated by
// the first two bytes of this CONSTANT_Class item
return readUTF8(items[readUnsignedShort(index)], buf);
return readStringish(index, buf);
}
/**
* Reads a CONSTANT_Module_info item in {@code b}. This method is intended
* for {@link Attribute} sub classes, and is normally not needed by class
* generators or adapters.
* Reads a module constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified module item.
*/
public String readModule(int index, char[] buf) {
return readUTF8(items[readUnsignedShort(index)], buf);
public String readModule(final int index, final char[] buf) {
return readStringish(index, buf);
}
/**
* Reads a CONSTANT_Package_info item in {@code b}. This method is
* intended for {@link Attribute} sub slasses, and is normally not needed
* by class generators or adapters.
* Reads a module constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a package constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified package item.
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified module item.
*/
public String readPackage(int index, char[] buf) {
return readUTF8(items[readUnsignedShort(index)], buf);
public String readPackage(final int index, final char[] buf) {
return readStringish(index, buf);
}
/**
@@ -2550,8 +2769,6 @@ public class ClassReader {
case ClassWriter.DOUBLE:
return Double.longBitsToDouble(readLong(index));
case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
return Type.getObjectType(readUTF8(index, buf));
case ClassWriter.STR:
return readUTF8(index, buf);

View File

@@ -60,11 +60,11 @@ package org.redkale.asm;
/**
* A visitor to visit a Java class. The methods of this class must be called in
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
* <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
* <tt>visitEnd</tt>.
* the following order: &#60;tt&#62;visit&#60;/tt&#62; [ &#60;tt&#62;visitSource&#60;/tt&#62; ] [
* &#60;tt&#62;visitModule&#60;/tt&#62; ][ &#60;tt&#62;visitOuterClass&#60;/tt&#62; ] ( &#60;tt&#62;visitAnnotation&#60;/tt&#62; |
* &#60;tt&#62;visitTypeAnnotation&#60;/tt&#62; | &#60;tt&#62;visitAttribute&#60;/tt&#62; )* (
* &#60;tt&#62;visitInnerClass&#60;/tt&#62; | &#60;tt&#62;visitField&#60;/tt&#62; | &#60;tt&#62;visitMethod&#60;/tt&#62; )*
* &#60;tt&#62;visitEnd&#60;/tt&#62;.
*
* @author Eric Bruneton
*/
@@ -72,7 +72,7 @@ public abstract class ClassVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -87,7 +87,7 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public ClassVisitor(final int api) {
this(api, null);
@@ -98,15 +98,12 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param cv
* the class visitor to which this visitor must delegate method
* calls. May be null.
*/
public ClassVisitor(final int api, final ClassVisitor cv) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.cv = cv;
}
@@ -123,18 +120,18 @@ public abstract class ClassVisitor {
* the internal name of the class (see
* {@link Type#getInternalName() getInternalName}).
* @param signature
* the signature of this class. May be <tt>null</tt> if the class
* the signature of this class. May be &#60;tt&#62;null&#60;/tt&#62; if the class
* is not a generic one, and does not extend or implement generic
* classes or interfaces.
* @param superName
* the internal of name of the super class (see
* {@link Type#getInternalName() getInternalName}). For
* interfaces, the super class is {@link Object}. May be
* <tt>null</tt>, but only for the {@link Object} class.
* &#60;tt&#62;null&#60;/tt&#62;, but only for the {@link Object} class.
* @param interfaces
* the internal names of the class's interfaces (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* &#60;tt&#62;null&#60;/tt&#62;.
*/
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
@@ -148,11 +145,11 @@ public abstract class ClassVisitor {
*
* @param source
* the name of the source file from which the class was compiled.
* May be <tt>null</tt>.
* May be &#60;tt&#62;null&#60;/tt&#62;.
* @param debug
* additional debug information to compute the correspondance
* between source and compiled elements of the class. May be
* <tt>null</tt>.
* &#60;tt&#62;null&#60;/tt&#62;.
*/
public void visitSource(String source, String debug) {
if (cv != null) {
@@ -160,6 +157,28 @@ public abstract class ClassVisitor {
}
}
/**
* Visit the module corresponding to the class.
* @param name
* module name
* @param access
* module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
* and {@code ACC_MANDATED}.
* @param version
* module version or null.
* @return a visitor to visit the module values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this module.
*/
public ModuleVisitor visitModule(String name, int access, String version) {
if (api < Opcodes.ASM6) {
throw new RuntimeException();
}
if (cv != null) {
return cv.visitModule(name, access, version);
}
return null;
}
/**
* Visits the enclosing class of the class. This method must be called only
* if the class has an enclosing class.
@@ -168,11 +187,11 @@ public abstract class ClassVisitor {
* internal name of the enclosing class of the class.
* @param name
* the name of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* &#60;tt&#62;null&#60;/tt&#62; if the class is not enclosed in a method of its
* enclosing class.
* @param desc
* the descriptor of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* &#60;tt&#62;null&#60;/tt&#62; if the class is not enclosed in a method of its
* enclosing class.
*/
public void visitOuterClass(String owner, String name, String desc) {
@@ -187,8 +206,8 @@ public abstract class ClassVisitor {
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
@@ -212,19 +231,16 @@ public abstract class ClassVisitor {
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
@@ -253,10 +269,10 @@ public abstract class ClassVisitor {
* @param outerName
* the internal name of the class to which the inner class
* belongs (see {@link Type#getInternalName() getInternalName}).
* May be <tt>null</tt> for not member classes.
* May be &#60;tt&#62;null&#60;/tt&#62; for not member classes.
* @param innerName
* the (simple) name of the inner class inside its enclosing
* class. May be <tt>null</tt> for anonymous inner classes.
* class. May be &#60;tt&#62;null&#60;/tt&#62; for anonymous inner classes.
* @param access
* the access flags of the inner class as originally declared in
* the enclosing class.
@@ -279,20 +295,20 @@ public abstract class ClassVisitor {
* @param desc
* the field's descriptor (see {@link Type Type}).
* @param signature
* the field's signature. May be <tt>null</tt> if the field's
* the field's signature. May be &#60;tt&#62;null&#60;/tt&#62; if the field's
* type does not use generic types.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* &#60;tt&#62;null&#60;/tt&#62; if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String} (for <tt>int</tt>,
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
* {@link Double} or a {@link String} (for &#60;tt&#62;int&#60;/tt&#62;,
* &#60;tt&#62;float&#60;/tt&#62;, &#60;tt&#62;long&#60;/tt&#62; or &#60;tt&#62;String&#60;/tt&#62; fields
* respectively). <i>This parameter is only used for static
* fields</i>. Its value is ignored for non static fields, which
* must be initialized through bytecode instructions in
* constructors or methods.
* @return a visitor to visit field annotations and attributes, or
* <tt>null</tt> if this class visitor is not interested in visiting
* &#60;tt&#62;null&#60;/tt&#62; if this class visitor is not interested in visiting
* these annotations and attributes.
*/
public FieldVisitor visitField(int access, String name, String desc,
@@ -305,7 +321,7 @@ public abstract class ClassVisitor {
/**
* Visits a method of the class. This method <i>must</i> return a new
* {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
* {@link MethodVisitor} instance (or &#60;tt&#62;null&#60;/tt&#62;) each time it is called,
* i.e., it should not return a previously returned visitor.
*
* @param access
@@ -317,14 +333,14 @@ public abstract class ClassVisitor {
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param signature
* the method's signature. May be <tt>null</tt> if the method
* the method's signature. May be &#60;tt&#62;null&#60;/tt&#62; if the method
* parameters, return type and exceptions do not use generic
* types.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* @return an object to visit the byte code of the method, or <tt>null</tt>
* &#60;tt&#62;null&#60;/tt&#62;.
* @return an object to visit the byte code of the method, or &#60;tt&#62;null&#60;/tt&#62;
* if this class visitor is not interested in visiting the code of
* this method.
*/

View File

@@ -87,8 +87,8 @@ public class ClassWriter extends ClassVisitor {
* {@link MethodVisitor#visitFrame} method are ignored, and the stack map
* frames are recomputed from the methods bytecode. The arguments of the
* {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
* recomputed from the bytecode. In other words, computeFrames implies
* computeMaxs.
* recomputed from the bytecode. In other words, COMPUTE_FRAMES implies
* COMPUTE_MAXS.
*
* @see #ClassWriter(int)
*/
@@ -196,6 +196,27 @@ public class ClassWriter extends ClassVisitor {
*/
static final int WIDE_INSN = 17;
/**
* The type of the ASM pseudo instructions with an unsigned 2 bytes offset
* label (see Label#resolve).
*/
static final int ASM_LABEL_INSN = 18;
/**
* The type of the ASM pseudo instructions with a 4 bytes offset label.
*/
static final int ASM_LABELW_INSN = 19;
/**
* Represents a frame inserted between already existing frames. This kind of
* frame can only be used if the frame content can be computed from the
* previous existing frame and from the instructions between this existing
* frame and the inserted one, without any knowledge of the type hierarchy.
* This kind of frame is only used when an unconditional jump is inserted in
* a method while expanding an ASM pseudo instruction (see ClassReader).
*/
static final int F_INSERT = 256;
/**
* The instruction types of all JVM opcodes.
*/
@@ -284,7 +305,7 @@ public class ClassWriter extends ClassVisitor {
/**
* The base value for all CONSTANT_MethodHandle constant pool items.
* Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
* different items.
* different items (from 21 to 29).
*/
static final int HANDLE_BASE = 20;
@@ -370,8 +391,8 @@ public class ClassWriter extends ClassVisitor {
* A type table used to temporarily store internal names that will not
* necessarily be stored in the constant pool. This type table is used by
* the control flow and data flow analysis algorithm used to compute stack
* map frames from scratch. This array associates to each index <tt>i</tt>
* the Item whose index is <tt>i</tt>. All Item objects stored in this array
* map frames from scratch. This array associates to each index &#60;tt&#62;i&#60;/tt&#62;
* the Item whose index is &#60;tt&#62;i&#60;/tt&#62;. All Item objects stored in this array
* are also stored in the {@link #items} hash table. These two arrays allow
* to retrieve an Item from its index or, conversely, to get the index of an
* Item from its value. Each Item stores an internal name in its
@@ -433,6 +454,11 @@ public class ClassWriter extends ClassVisitor {
*/
private ByteVector sourceDebug;
/**
* The module attribute of this class.
*/
private ModuleWriter moduleWriter;
/**
* The constant pool item that contains the name of the enclosing class of
* this class.
@@ -523,25 +549,19 @@ public class ClassWriter extends ClassVisitor {
MethodWriter lastMethod;
/**
* <tt>true</tt> if the maximum stack size and number of local variables
* must be automatically computed.
* Indicates what must be automatically computed.
*
* @see MethodWriter#compute
*/
private boolean computeMaxs;
private int compute;
/**
* <tt>true</tt> if the stack map frames must be recomputed from scratch.
* &#60;tt&#62;true&#60;/tt&#62; if some methods have wide forward jumps using ASM pseudo
* instructions, which need to be expanded into sequences of standard
* bytecode instructions. In this case the class is re-read and re-written
* with a ClassReader -> ClassWriter chain to perform this transformation.
*/
private boolean computeFrames;
/**
* <tt>true</tt> if the stack map tables of this class are invalid. The
* {@link MethodWriter#resizeInstructions} method cannot transform existing
* stack map tables, and so produces potentially invalid classes when it is
* executed. In this case the class is reread and rewritten with the
* {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize
* stack map tables when this option is used).
*/
boolean invalidFrames;
boolean hasAsmInsns;
// ------------------------------------------------------------------------
// Static initializer
@@ -552,11 +572,11 @@ public class ClassWriter extends ClassVisitor {
*/
static {
int i;
byte[] b = new byte[220];
byte[] b = new byte[221];
String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
+ "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
+ "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ";
+ "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST";
for (i = 0; i < b.length; ++i) {
b[i] = (byte) (s.charAt(i) - 'A');
}
@@ -610,8 +630,9 @@ public class ClassWriter extends ClassVisitor {
// // temporary opcodes used internally by ASM - see Label and
// MethodWriter
// for (i = 202; i < 220; ++i) {
// b[i] = LABEL_INSN;
// b[i] = ASM_LABEL_INSN;
// }
// b[220] = ASM_LABELW_INSN;
//
// // LDC(_W) instructions
// b[Constants.LDC] = LDC_INSN;
@@ -644,7 +665,7 @@ public class ClassWriter extends ClassVisitor {
* {@link #COMPUTE_FRAMES}.
*/
public ClassWriter(final int flags) {
super(Opcodes.ASM5);
super(Opcodes.ASM6);
index = 1;
pool = new ByteVector();
items = new Item[256];
@@ -653,8 +674,9 @@ public class ClassWriter extends ClassVisitor {
key2 = new Item();
key3 = new Item();
key4 = new Item();
this.computeMaxs = (flags & COMPUTE_MAXS) != 0;
this.computeFrames = (flags & COMPUTE_FRAMES) != 0;
this.compute = (flags & COMPUTE_FRAMES) != 0 ? MethodWriter.FRAMES
: ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS
: MethodWriter.NOTHING);
}
/**
@@ -684,9 +706,9 @@ public class ClassWriter extends ClassVisitor {
* @param flags
* option flags that can be used to modify the default behavior
* of this class. <i>These option flags do not affect methods
* that are copied as is in the new class. This means that the
* maximum stack size nor the stack frames will be computed for
* these methods</i>. See {@link #COMPUTE_MAXS},
* that are copied as is in the new class. This means that
* neither the maximum stack size nor the stack frames will be
* computed for these methods</i>. See {@link #COMPUTE_MAXS},
* {@link #COMPUTE_FRAMES}.
*/
public ClassWriter(final ClassReader classReader, final int flags) {
@@ -705,9 +727,9 @@ public class ClassWriter extends ClassVisitor {
final String[] interfaces) {
this.version = version;
this.access = access;
this.name = (name == null) ? 0 : newClass(name);
this.name = newClass(name);
thisName = name;
if (ClassReader.SIGNATURES && signature != null) {
if (signature != null) {
this.signature = newUTF8(signature);
}
this.superName = superName == null ? 0 : newClass(superName);
@@ -731,6 +753,14 @@ public class ClassWriter extends ClassVisitor {
}
}
@Override
public final ModuleVisitor visitModule(final String name,
final int access, final String version) {
return moduleWriter = new ModuleWriter(this,
newModule(name), access,
version == null ? 0 : newUTF8(version));
}
@Override
public final void visitOuterClass(final String owner, final String name,
final String desc) {
@@ -743,9 +773,6 @@ public class ClassWriter extends ClassVisitor {
@Override
public final AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(newUTF8(desc)).putShort(0);
@@ -763,9 +790,6 @@ public class ClassWriter extends ClassVisitor {
@Override
public final AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
@@ -805,7 +829,7 @@ public class ClassWriter extends ClassVisitor {
// and equality tests). If so we store the index of this inner class
// entry (plus one) in intVal. This hack allows duplicate detection in
// O(1) time.
Item nameItem = newClassItem(name);
Item nameItem = newStringishItem(CLASS, name);
if (nameItem.intVal == 0) {
++innerClassesCount;
innerClasses.putShort(nameItem.index);
@@ -830,7 +854,7 @@ public class ClassWriter extends ClassVisitor {
public final MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
return new MethodWriter(this, access, name, desc, signature,
exceptions, computeMaxs, computeFrames);
exceptions, compute);
}
@Override
@@ -874,7 +898,7 @@ public class ClassWriter extends ClassVisitor {
size += 8 + bootstrapMethods.length;
newUTF8("BootstrapMethods");
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
++attributeCount;
size += 8;
newUTF8("Signature");
@@ -912,26 +936,31 @@ public class ClassWriter extends ClassVisitor {
size += 8 + innerClasses.length;
newUTF8("InnerClasses");
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
++attributeCount;
size += 8 + anns.getSize();
newUTF8("RuntimeVisibleAnnotations");
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
++attributeCount;
size += 8 + ianns.getSize();
newUTF8("RuntimeInvisibleAnnotations");
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
++attributeCount;
size += 8 + tanns.getSize();
newUTF8("RuntimeVisibleTypeAnnotations");
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
++attributeCount;
size += 8 + itanns.getSize();
newUTF8("RuntimeInvisibleTypeAnnotations");
}
if (moduleWriter != null) {
attributeCount += 1 + moduleWriter.attributeCount;
size += 6 + moduleWriter.size + moduleWriter.attributesSize;
newUTF8("Module");
}
if (attrs != null) {
attributeCount += attrs.getCount();
size += attrs.getSize(this, null, 0, -1, -1);
@@ -968,7 +997,7 @@ public class ClassWriter extends ClassVisitor {
bootstrapMethodsCount);
out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
}
if (sourceFile != 0) {
@@ -979,6 +1008,11 @@ public class ClassWriter extends ClassVisitor {
out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
out.putByteArray(sourceDebug.data, 0, len);
}
if (moduleWriter != null) {
out.putShort(newUTF8("Module"));
moduleWriter.put(out);
moduleWriter.putAttributes(out);
}
if (enclosingMethodOwner != 0) {
out.putShort(newUTF8("EnclosingMethod")).putInt(4);
out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
@@ -997,41 +1031,46 @@ public class ClassWriter extends ClassVisitor {
out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
out.putByteArray(innerClasses.data, 0, innerClasses.length);
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
out.putShort(newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}
if (attrs != null) {
attrs.put(this, null, 0, -1, -1, out);
}
if (invalidFrames) {
if (hasAsmInsns) {
boolean hasFrames = false;
mb = firstMethod;
while (mb != null) {
hasFrames |= mb.frameCount > 0;
mb = (MethodWriter) mb.mv;
}
anns = null;
ianns = null;
attrs = null;
innerClassesCount = 0;
innerClasses = null;
bootstrapMethodsCount = 0;
bootstrapMethods = null;
moduleWriter = null;
firstField = null;
lastField = null;
firstMethod = null;
lastMethod = null;
computeMaxs = false;
computeFrames = true;
invalidFrames = false;
new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
compute =
hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING;
hasAsmInsns = false;
new ClassReader(out.data).accept(this,
(hasFrames ? ClassReader.EXPAND_FRAMES : 0)
| ClassReader.EXPAND_ASM_INSNS);
return toByteArray();
}
return out.data;
@@ -1078,16 +1117,16 @@ public class ClassWriter extends ClassVisitor {
double val = ((Double) cst).doubleValue();
return newDouble(val);
} else if (cst instanceof String) {
return newString((String) cst);
return newStringishItem(STR, (String) cst);
} else if (cst instanceof Type) {
Type t = (Type) cst;
int s = t.getSort();
if (s == Type.OBJECT) {
return newClassItem(t.getInternalName());
return newStringishItem(CLASS, t.getInternalName());
} else if (s == Type.METHOD) {
return newMethodTypeItem(t.getDescriptor());
return newStringishItem(MTYPE, t.getDescriptor());
} else { // s == primitive type or array
return newClassItem(t.getDescriptor());
return newStringishItem(CLASS, t.getDescriptor());
}
} else if (cst instanceof Handle) {
Handle h = (Handle) cst;
@@ -1136,20 +1175,21 @@ public class ClassWriter extends ClassVisitor {
}
/**
* Adds a class reference to the constant pool of the class being build.
* Adds a string reference, a class reference, a method type, a module
* or a package to the constant pool of the class being build.
* Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param type
* a type among STR, CLASS, MTYPE, MODULE or PACKAGE
* @param value
* the internal name of the class.
* @return a new or already existing class reference item.
* string value of the reference.
* @return a new or already existing reference item.
*/
Item newClassItem(final String value) {
key2.set(CLASS, value, null, null);
Item newStringishItem(final int type, final String value) {
key2.set(type, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(CLASS, newUTF8(value));
pool.put12(type, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
@@ -1167,72 +1207,7 @@ public class ClassWriter extends ClassVisitor {
* @return the index of a new or already existing class reference item.
*/
public int newClass(final String value) {
return newClassItem(value).index;
}
/**
* Adds a module name to the constant pool.
*
* Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param value
* the module name
* @return the index of a new or already existing module reference item.
*/
public int newModule(String value) {
key2.set(MODULE, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(MODULE, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result.index;
}
/**
* Adds a package name to the constant pool.
*
* Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param value
* the internal name of the package.
* @return the index of a new or already existing package reference item.
*/
public int newPackage(String value) {
key2.set(PACKAGE, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(PACKAGE, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result.index;
}
/**
* Adds a method type reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param methodDesc
* method descriptor of the method type.
* @return a new or already existing method type reference item.
*/
Item newMethodTypeItem(final String methodDesc) {
key2.set(MTYPE, methodDesc, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(MTYPE, newUTF8(methodDesc));
result = new Item(index++, key2);
put(result);
}
return result;
return newStringishItem(CLASS, value).index;
}
/**
@@ -1247,7 +1222,37 @@ public class ClassWriter extends ClassVisitor {
* item.
*/
public int newMethodType(final String methodDesc) {
return newMethodTypeItem(methodDesc).index;
return newStringishItem(MTYPE, methodDesc).index;
}
/**
* Adds a module reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param moduleName
* name of the module.
* @return the index of a new or already existing module reference
* item.
*/
public int newModule(final String moduleName) {
return newStringishItem(MODULE, moduleName).index;
}
/**
* Adds a package reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param packageName
* name of the package in its internal form.
* @return the index of a new or already existing module reference
* item.
*/
public int newPackage(final String packageName) {
return newStringishItem(PACKAGE, packageName).index;
}
/**
@@ -1292,38 +1297,6 @@ public class ClassWriter extends ClassVisitor {
return result;
}
/**
* Adds a handle to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param tag
* the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
* {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the field or method owner class.
* @param name
* the name of the field or method.
* @param desc
* the descriptor of the field or method.
* @return the index of a new or already existing method type reference
* item.
*
* @deprecated this method is superseded by
* {@link #newHandle(int, String, String, String, boolean)}.
*/
@Deprecated
public int newHandle(final int tag, final String owner, final String name,
final String desc) {
return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
}
/**
* Adds a handle to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item. <i>This method is
@@ -1513,7 +1486,7 @@ public class ClassWriter extends ClassVisitor {
* @param desc
* the method's descriptor.
* @param itf
* <tt>true</tt> if <tt>owner</tt> is an interface.
* &#60;tt&#62;true&#60;/tt&#62; if &#60;tt&#62;owner&#60;/tt&#62; is an interface.
* @return a new or already existing method reference item.
*/
Item newMethodItem(final String owner, final String name,
@@ -1542,7 +1515,7 @@ public class ClassWriter extends ClassVisitor {
* @param desc
* the method's descriptor.
* @param itf
* <tt>true</tt> if <tt>owner</tt> is an interface.
* &#60;tt&#62;true&#60;/tt&#62; if &#60;tt&#62;owner&#60;/tt&#62; is an interface.
* @return the index of a new or already existing method reference item.
*/
public int newMethod(final String owner, final String name,
@@ -1628,25 +1601,6 @@ public class ClassWriter extends ClassVisitor {
return result;
}
/**
* Adds a string to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item.
*
* @param value
* the String value.
* @return a new or already existing string item.
*/
private Item newString(final String value) {
key2.set(STR, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(STR, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result;
}
/**
* Adds a name and type to the constant pool of the class being build. Does
* nothing if the constant pool already contains a similar item. <i>This
@@ -1824,7 +1778,7 @@ public class ClassWriter extends ClassVisitor {
* @param key
* a constant pool item.
* @return the constant pool's hash table item which is equal to the given
* item, or <tt>null</tt> if there is no such item.
* item, or &#60;tt&#62;null&#60;/tt&#62; if there is no such item.
*/
private Item get(final Item key) {
Item i = items[key.hashCode % items.length];

View File

@@ -0,0 +1,85 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* Information about the input stack map frame at the "current" instruction of a
* method. This is implemented as a Frame subclass for a "basic block"
* containing only one instruction.
*
* @author Eric Bruneton
*/
class CurrentFrame extends Frame {
/**
* Sets this CurrentFrame to the input stack map frame of the next "current"
* instruction, i.e. the instruction just after the given one. It is assumed
* that the value of this object when this method is called is the stack map
* frame status just before the given instruction is executed.
*/
@Override
void execute(int opcode, int arg, ClassWriter cw, Item item) {
super.execute(opcode, arg, cw, item);
Frame successor = new Frame();
merge(cw, successor, 0);
set(successor);
owner.inputStackTop = 0;
}
}

View File

@@ -60,8 +60,8 @@ package org.redkale.asm;
/**
* A visitor to visit a Java field. The methods of this class must be called in
* the following order: ( <tt>visitAnnotation</tt> |
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
* the following order: ( &#60;tt&#62;visitAnnotation&#60;/tt&#62; |
* &#60;tt&#62;visitTypeAnnotation&#60;/tt&#62; | &#60;tt&#62;visitAttribute&#60;/tt&#62; )* &#60;tt&#62;visitEnd&#60;/tt&#62;.
*
* @author Eric Bruneton
*/
@@ -69,7 +69,7 @@ public abstract class FieldVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -84,7 +84,7 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public FieldVisitor(final int api) {
this(api, null);
@@ -95,15 +95,12 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param fv
* the field visitor to which this visitor must delegate method
* calls. May be null.
*/
public FieldVisitor(final int api, final FieldVisitor fv) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.fv = fv;
}
@@ -114,8 +111,8 @@ public abstract class FieldVisitor {
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
@@ -135,19 +132,16 @@ public abstract class FieldVisitor {
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}

View File

@@ -100,28 +100,28 @@ final class FieldWriter extends FieldVisitor {
private int value;
/**
* The runtime visible annotations of this field. May be <tt>null</tt>.
* The runtime visible annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;.
*/
private AnnotationWriter anns;
/**
* The runtime invisible annotations of this field. May be <tt>null</tt>.
* The runtime invisible annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;.
*/
private AnnotationWriter ianns;
/**
* The runtime visible type annotations of this field. May be <tt>null</tt>.
* The runtime visible type annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;.
*/
private AnnotationWriter tanns;
/**
* The runtime invisible type annotations of this field. May be
* <tt>null</tt>.
* &#60;tt&#62;null&#60;/tt&#62;.
*/
private AnnotationWriter itanns;
/**
* The non standard attributes of this field. May be <tt>null</tt>.
* The non standard attributes of this field. May be &#60;tt&#62;null&#60;/tt&#62;.
*/
private Attribute attrs;
@@ -141,13 +141,13 @@ final class FieldWriter extends FieldVisitor {
* @param desc
* the field's descriptor (see {@link Type}).
* @param signature
* the field's signature. May be <tt>null</tt>.
* the field's signature. May be &#60;tt&#62;null&#60;/tt&#62;.
* @param value
* the field's constant value. May be <tt>null</tt>.
* the field's constant value. May be &#60;tt&#62;null&#60;/tt&#62;.
*/
FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) {
super(Opcodes.ASM5);
super(Opcodes.ASM6);
if (cw.firstField == null) {
cw.firstField = this;
} else {
@@ -158,7 +158,7 @@ final class FieldWriter extends FieldVisitor {
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
if (ClassReader.SIGNATURES && signature != null) {
if (signature != null) {
this.signature = cw.newUTF8(signature);
}
if (value != null) {
@@ -173,9 +173,6 @@ final class FieldWriter extends FieldVisitor {
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
@@ -193,9 +190,6 @@ final class FieldWriter extends FieldVisitor {
@Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
@@ -249,23 +243,23 @@ final class FieldWriter extends FieldVisitor {
cw.newUTF8("Deprecated");
size += 6;
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
cw.newUTF8("Signature");
size += 8;
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize();
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + tanns.getSize();
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + itanns.getSize();
}
@@ -299,19 +293,19 @@ final class FieldWriter extends FieldVisitor {
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount;
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
++attributeCount;
}
if (attrs != null) {
@@ -331,23 +325,23 @@ final class FieldWriter extends FieldVisitor {
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
out.putShort(cw.newUTF8("Signature"));
out.putInt(2).putShort(signature);
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}

View File

@@ -63,7 +63,7 @@ package org.redkale.asm;
*
* @author Eric Bruneton
*/
final class Frame {
class Frame {
/*
* Frames are computed in a two steps process: during the visit of each
@@ -192,7 +192,7 @@ final class Frame {
private static final int LOCAL = 0x2000000;
/**
* Kind of the the types that are relative to the stack of an input stack
* Kind of the types that are relative to the stack of an input stack
* map frame. The value of such types is a position relatively to the top of
* this stack.
*/
@@ -525,7 +525,7 @@ final class Frame {
* When the stack map frames are completely computed, this field is the
* actual number of types in {@link #outputStack}.
*/
private int outputStackTop;
int outputStackTop;
/**
* Number of types that are initialized in the basic block.
@@ -549,6 +549,110 @@ final class Frame {
*/
private int[] initializations;
/**
* Sets this frame to the given value.
*
* @param cw
* the ClassWriter to which this label belongs.
* @param nLocal
* the number of local variables.
* @param local
* the local variable types. Primitive types are represented by
* {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
* {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are
* represented by a single element). Reference types are
* represented by String objects (representing internal names),
* and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized
* value).
* @param nStack
* the number of operand stack elements.
* @param stack
* the operand stack types (same format as the "local" array).
*/
final void set(ClassWriter cw, final int nLocal, final Object[] local,
final int nStack, final Object[] stack) {
int i = convert(cw, nLocal, local, inputLocals);
while (i < local.length) {
inputLocals[i++] = TOP;
}
int nStackTop = 0;
for (int j = 0; j < nStack; ++j) {
if (stack[j] == Opcodes.LONG || stack[j] == Opcodes.DOUBLE) {
++nStackTop;
}
}
inputStack = new int[nStack + nStackTop];
convert(cw, nStack, stack, inputStack);
outputStackTop = 0;
initializationCount = 0;
}
/**
* Converts types from the MethodWriter.visitFrame() format to the Frame
* format.
*
* @param cw
* the ClassWriter to which this label belongs.
* @param nInput
* the number of types to convert.
* @param input
* the types to convert. Primitive types are represented by
* {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
* {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are
* represented by a single element). Reference types are
* represented by String objects (representing internal names),
* and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized
* value).
* @param output
* where to store the converted types.
* @return the number of output elements.
*/
private static int convert(ClassWriter cw, int nInput, Object[] input,
int[] output) {
int i = 0;
for (int j = 0; j < nInput; ++j) {
if (input[j] instanceof Integer) {
output[i++] = BASE | ((Integer) input[j]).intValue();
if (input[j] == Opcodes.LONG || input[j] == Opcodes.DOUBLE) {
output[i++] = TOP;
}
} else if (input[j] instanceof String) {
output[i++] = type(cw, Type.getObjectType((String) input[j])
.getDescriptor());
} else {
output[i++] = UNINITIALIZED
| cw.addUninitializedType("",
((Label) input[j]).position);
}
}
return i;
}
/**
* Sets this frame to the value of the given frame. WARNING: after this
* method is called the two frames share the same data structures. It is
* recommended to discard the given frame f to avoid unexpected side
* effects.
*
* @param f
* The new frame value.
*/
final void set(final Frame f) {
inputLocals = f.inputLocals;
inputStack = f.inputStack;
outputLocals = f.outputLocals;
outputStack = f.outputStack;
outputStackTop = f.outputStackTop;
initializationCount = f.initializationCount;
initializations = f.initializations;
}
/**
* Returns the output frame local variable type at the given index.
*
@@ -614,7 +718,7 @@ final class Frame {
}
// pushes the type on the output stack
outputStack[outputStackTop++] = type;
// updates the maximun height reached by the output stack, if needed
// updates the maximum height reached by the output stack, if needed
int top = owner.inputStackTop + outputStackTop;
if (top > owner.outputStackMax) {
owner.outputStackMax = top;
@@ -650,7 +754,7 @@ final class Frame {
* a type descriptor.
* @return the int encoding of the given type.
*/
private static int type(final ClassWriter cw, final String desc) {
static int type(final ClassWriter cw, final String desc) {
String t;
int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
switch (desc.charAt(index)) {
@@ -838,7 +942,7 @@ final class Frame {
* @param maxLocals
* the maximum number of local variables of this method.
*/
void initInputFrame(final ClassWriter cw, final int access,
final void initInputFrame(final ClassWriter cw, final int access,
final Type[] args, final int maxLocals) {
inputLocals = new int[maxLocals];
inputStack = new int[0];
@@ -981,7 +1085,7 @@ final class Frame {
case Opcodes.AALOAD:
pop(1);
t1 = pop();
push(ELEMENT_OF + t1);
push(t1 == NULL ? t1 : ELEMENT_OF + t1);
break;
case Opcodes.ISTORE:
case Opcodes.FSTORE:
@@ -1299,7 +1403,7 @@ final class Frame {
/**
* Merges the input frame of the given basic block with the input and output
* frames of this basic block. Returns <tt>true</tt> if the input frame of
* frames of this basic block. Returns &#60;tt&#62;true&#60;/tt&#62; if the input frame of
* the given label has been changed by this operation.
*
* @param cw
@@ -1309,10 +1413,10 @@ final class Frame {
* @param edge
* the kind of the {@link Edge} between this label and 'label'.
* See {@link Edge#info}.
* @return <tt>true</tt> if the input frame of the given label has been
* @return &#60;tt&#62;true&#60;/tt&#62; if the input frame of the given label has been
* changed by this operation.
*/
boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
boolean changed = false;
int i, s, dim, kind, t;
@@ -1407,7 +1511,7 @@ final class Frame {
/**
* Merges the type at the given index in the given type array with the given
* type. Returns <tt>true</tt> if the type array has been modified by this
* type. Returns &#60;tt&#62;true&#60;/tt&#62; if the type array has been modified by this
* operation.
*
* @param cw
@@ -1418,7 +1522,7 @@ final class Frame {
* an array of types.
* @param index
* the index of the type that must be merged in 'types'.
* @return <tt>true</tt> if the type array has been modified by this
* @return &#60;tt&#62;true&#60;/tt&#62; if the type array has been modified by this
* operation.
*/
private static boolean merge(final ClassWriter cw, int t,

View File

@@ -99,35 +99,6 @@ public final class Handle {
*/
final boolean itf;
/**
* Constructs a new field or method handle.
*
* @param tag
* the kind of field or method designated by this Handle. Must be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the class that owns the field or method
* designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
* the descriptor of the field or method designated by this
* handle.
*
* @deprecated this constructor has been superseded
* by {@link #Handle(int, String, String, String, boolean)}.
*/
@Deprecated
public Handle(int tag, String owner, String name, String desc) {
this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
}
/**
* Constructs a new field or method handle.
*

View File

@@ -82,7 +82,7 @@ class Handler {
/**
* Internal name of the type of exceptions handled by this handler, or
* <tt>null</tt> to catch any exceptions.
* &#60;tt&#62;null&#60;/tt&#62; to catch any exceptions.
*/
String desc;

View File

@@ -80,6 +80,7 @@ final class Item {
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
* {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
* {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
*
* MethodHandle constant 9 variations are stored using a range of 9 values
@@ -239,12 +240,12 @@ final class Item {
this.strVal3 = strVal3;
switch (type) {
case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.MTYPE:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return;
@@ -305,8 +306,8 @@ final class Item {
* @param i
* the item to be compared to this one. Both items must have the
* same {@link #type}.
* @return <tt>true</tt> if the given item if equal to this one,
* <tt>false</tt> otherwise.
* @return &#60;tt&#62;true&#60;/tt&#62; if the given item if equal to this one,
* &#60;tt&#62;false&#60;/tt&#62; otherwise.
*/
boolean isEqualTo(final Item i) {
switch (type) {

View File

@@ -139,7 +139,8 @@ public class Label {
/**
* Field used to associate user information to a label. Warning: this field
* is used by the ASM tree package. In order to use it with the ASM tree
* package you must override the method.
* package you must override the
*
*/
public Object info;
@@ -324,8 +325,8 @@ public class Label {
* the position of first byte of the bytecode instruction that
* contains this label.
* @param wideOffset
* <tt>true</tt> if the reference must be stored in 4 bytes, or
* <tt>false</tt> if it must be stored with 2 bytes.
* &#60;tt&#62;true&#60;/tt&#62; if the reference must be stored in 4 bytes, or
* &#60;tt&#62;false&#60;/tt&#62; if it must be stored with 2 bytes.
* @throws IllegalArgumentException
* if this label has not been created by the given code writer.
*/
@@ -388,13 +389,12 @@ public class Label {
* the position of this label in the bytecode.
* @param data
* the bytecode of the method.
* @return <tt>true</tt> if a blank that was left for this label was to
* @return &#60;tt&#62;true&#60;/tt&#62; if a blank that was left for this label was too
* small to store the offset. In such a case the corresponding jump
* instruction is replaced with a pseudo instruction (using unused
* opcodes) using an unsigned two bytes offset. These pseudo
* instructions will need to be replaced with true instructions with
* wider offsets (4 bytes instead of 2). This is done in
* {@link MethodWriter#resizeInstructions}.
* instructions will be replaced with standard bytecode instructions
* with wider offsets (4 bytes instead of 2), in ClassReader.
* @throws IllegalArgumentException
* if this label has already been resolved, or if it has not
* been created by the given code writer.
@@ -453,7 +453,7 @@ public class Label {
* @return the first label of the series to which this label belongs.
*/
Label getFirst() {
return !ClassReader.FRAMES || frame == null ? this : frame.owner;
return frame == null ? this : frame.owner;
}
// ------------------------------------------------------------------------

View File

@@ -5,7 +5,10 @@
*/
package org.redkale.asm;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import static org.redkale.asm.Opcodes.*;
/**
* MethodVisitor 的调试类
@@ -32,7 +35,7 @@ public class MethodDebugVisitor {
System.out.println();
}
private final Map<Label, Integer> labels = new LinkedHashMap();
private final Map<Label, Integer> labels = new LinkedHashMap<>();
private static final String[] opcodes = new String[200]; //0 -18
@@ -54,11 +57,20 @@ public class MethodDebugVisitor {
}
}
/**
*
* @param visitor MethodVisitor
*/
public MethodDebugVisitor(MethodVisitor visitor) {
//super(Opcodes.ASM5, visitor);
this.visitor = visitor;
}
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
visitor.visitTryCatchBlock(start, end, handler, type);
if (debug) System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");");
}
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln);
if (debug) System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");");
@@ -189,4 +201,74 @@ public class MethodDebugVisitor {
visitor.visitEnd();
if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n");
}
public static void pushInt(MethodDebugVisitor mv, int num) {
if (num < 6) {
mv.visitInsn(ICONST_0 + num);
} else if (num <= Byte.MAX_VALUE) {
mv.visitIntInsn(BIPUSH, num);
} else if (num <= Short.MAX_VALUE) {
mv.visitIntInsn(SIPUSH, num);
} else {
mv.visitLdcInsn(num);
}
}
public static void pushInt(MethodVisitor mv, int num) {
if (num < 6) {
mv.visitInsn(ICONST_0 + num);
} else if (num <= Byte.MAX_VALUE) {
mv.visitIntInsn(BIPUSH, num);
} else if (num <= Short.MAX_VALUE) {
mv.visitIntInsn(SIPUSH, num);
} else {
mv.visitLdcInsn(num);
}
}
public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
try {
for (Method anm : ann.annotationType().getMethods()) {
final String mname = anm.getName();
if ("equals".equals(mname) || "hashCode".equals(mname) || "toString".equals(mname) || "annotationType".equals(mname)) continue;
final Object r = anm.invoke(ann);
if (r instanceof String[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (String item : (String[]) r) {
av1.visit(null, item);
}
av1.visitEnd();
} else if (r instanceof Class[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (Class item : (Class[]) r) {
av1.visit(null, Type.getType(item));
}
av1.visitEnd();
} else if (r instanceof Enum[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (Enum item : (Enum[]) r) {
av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
}
av1.visitEnd();
} else if (r instanceof Annotation[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (Annotation item : (Annotation[]) r) {
visitAnnotation(av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), item);
}
av1.visitEnd();
} else if (r instanceof Class) {
av.visit(mname, Type.getType((Class) r));
} else if (r instanceof Enum) {
av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
} else if (r instanceof Annotation) {
visitAnnotation(av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), (Annotation) r);
} else {
av.visit(mname, r);
}
}
av.visitEnd();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -60,24 +60,24 @@ package org.redkale.asm;
/**
* A visitor to visit a Java method. The methods of this class must be called in
* the following order: ( <tt>visitParameter</tt> )* [
* <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
* <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> |
* <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
* <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> |
* <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> |
* <tt>visitTryCatchAnnotation</tt> | <tt>visitLocalVariable</tt> |
* <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )*
* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the
* <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must be called in
* the following order: ( &#60;tt&#62;visitParameter&#60;/tt&#62; )* [
* &#60;tt&#62;visitAnnotationDefault&#60;/tt&#62; ] ( &#60;tt&#62;visitAnnotation&#60;/tt&#62; |
* &#60;tt&#62;visitParameterAnnotation&#60;/tt&#62; &#60;tt&#62;visitTypeAnnotation&#60;/tt&#62; |
* &#60;tt&#62;visitAttribute&#60;/tt&#62; )* [ &#60;tt&#62;visitCode&#60;/tt&#62; ( &#60;tt&#62;visitFrame&#60;/tt&#62; |
* &#60;tt&#62;visit<i>X</i>Insn&#60;/tt&#62; | &#60;tt&#62;visitLabel&#60;/tt&#62; |
* &#60;tt&#62;visitInsnAnnotation&#60;/tt&#62; | &#60;tt&#62;visitTryCatchBlock&#60;/tt&#62; |
* &#60;tt&#62;visitTryCatchAnnotation&#60;/tt&#62; | &#60;tt&#62;visitLocalVariable&#60;/tt&#62; |
* &#60;tt&#62;visitLocalVariableAnnotation&#60;/tt&#62; | &#60;tt&#62;visitLineNumber&#60;/tt&#62; )*
* &#60;tt&#62;visitMaxs&#60;/tt&#62; ] &#60;tt&#62;visitEnd&#60;/tt&#62;. In addition, the
* &#60;tt&#62;visit<i>X</i>Insn&#60;/tt&#62; and &#60;tt&#62;visitLabel&#60;/tt&#62; methods must be called in
* the sequential order of the bytecode instructions of the visited code,
* <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
* instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
* &#60;tt&#62;visitInsnAnnotation&#60;/tt&#62; must be called <i>after</i> the annotated
* instruction, &#60;tt&#62;visitTryCatchBlock&#60;/tt&#62; must be called <i>before</i> the
* labels passed as arguments have been visited,
* <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
* &#60;tt&#62;visitTryCatchBlockAnnotation&#60;/tt&#62; must be called <i>after</i> the
* corresponding try catch block has been visited, and the
* <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
* <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
* &#60;tt&#62;visitLocalVariable&#60;/tt&#62;, &#60;tt&#62;visitLocalVariableAnnotation&#60;/tt&#62; and
* &#60;tt&#62;visitLineNumber&#60;/tt&#62; methods must be called <i>after</i> the labels
* passed as arguments have been visited.
*
* @author Eric Bruneton
@@ -86,7 +86,7 @@ public abstract class MethodVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -101,7 +101,7 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public MethodVisitor(final int api) {
this(api, null);
@@ -112,15 +112,12 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param mv
* the method visitor to which this visitor must delegate method
* calls. May be null.
*/
public MethodVisitor(final int api, final MethodVisitor mv) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.mv = mv;
}
@@ -135,14 +132,11 @@ public abstract class MethodVisitor {
* @param name
* parameter name or null if none is provided.
* @param access
* the parameter's access flags, only <tt>ACC_FINAL</tt>,
* <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
* the parameter's access flags, only &#60;tt&#62;ACC_FINAL&#60;/tt&#62;,
* &#60;tt&#62;ACC_SYNTHETIC&#60;/tt&#62; or/and &#60;tt&#62;ACC_MANDATED&#60;/tt&#62; are
* allowed (see {@link Opcodes}).
*/
public void visitParameter(String name, int access) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
mv.visitParameter(name, access);
}
@@ -152,7 +146,7 @@ public abstract class MethodVisitor {
* Visits the default value of this annotation interface method.
*
* @return a visitor to the visit the actual default value of this
* annotation interface method, or <tt>null</tt> if this visitor is
* annotation interface method, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is
* not interested in visiting this default value. The 'name'
* parameters passed to the methods of this annotation visitor are
* ignored. Moreover, exacly one visit method must be called on this
@@ -171,8 +165,8 @@ public abstract class MethodVisitor {
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
@@ -199,19 +193,16 @@ public abstract class MethodVisitor {
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
@@ -226,8 +217,8 @@ public abstract class MethodVisitor {
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitParameterAnnotation(int parameter,
@@ -453,35 +444,6 @@ public abstract class MethodVisitor {
}
}
/**
* Visits a method instruction. A method instruction is an instruction that
* invokes a method.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
*/
@Deprecated
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
/**
* Visits a method instruction. A method instruction is an instruction that
* invokes a method.
@@ -502,14 +464,6 @@ public abstract class MethodVisitor {
*/
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException(
"INVOKESPECIAL/STATIC on interfaces require ASM 5");
}
visitMethodInsn(opcode, owner, name, desc);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
@@ -614,7 +568,7 @@ public abstract class MethodVisitor {
* the constant to be loaded on the stack. This parameter must be
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
* ARRAY sort for <tt>.class</tt> constants, for classes whose
* ARRAY sort for &#60;tt&#62;.class&#60;/tt&#62; constants, for classes whose
* version is 49.0, a {@link Type} of METHOD sort or a
* {@link Handle} for MethodType and MethodHandle constants, for
* classes whose version is 51.0.
@@ -649,8 +603,8 @@ public abstract class MethodVisitor {
* @param dflt
* beginning of the default handler block.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>min + i</tt> key.
* beginnings of the handler blocks. &#60;tt&#62;labels[i]&#60;/tt&#62; is the
* beginning of the handler block for the &#60;tt&#62;min + i&#60;/tt&#62; key.
*/
public void visitTableSwitchInsn(int min, int max, Label dflt,
Label... labels) {
@@ -667,8 +621,8 @@ public abstract class MethodVisitor {
* @param keys
* the values of the keys.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>keys[i]</tt> key.
* beginnings of the handler blocks. &#60;tt&#62;labels[i]&#60;/tt&#62; is the
* beginning of the handler block for the &#60;tt&#62;keys[i]&#60;/tt&#62; key.
*/
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
if (mv != null) {
@@ -713,19 +667,16 @@ public abstract class MethodVisitor {
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
}
@@ -747,7 +698,7 @@ public abstract class MethodVisitor {
* beginning of the exception handler's code.
* @param type
* internal name of the type of exceptions handled by the
* handler, or <tt>null</tt> to catch any exceptions (for
* handler, or &#60;tt&#62;null&#60;/tt&#62; to catch any exceptions (for
* "finally" blocks).
* @throws IllegalArgumentException
* if one of the labels has already been visited by this visitor
@@ -773,19 +724,16 @@ public abstract class MethodVisitor {
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
}
@@ -801,7 +749,7 @@ public abstract class MethodVisitor {
* the type descriptor of this local variable.
* @param signature
* the type signature of this local variable. May be
* <tt>null</tt> if the local variable type does not use generic
* &#60;tt&#62;null&#60;/tt&#62; if the local variable type does not use generic
* types.
* @param start
* the first instruction corresponding to the scope of this local
@@ -833,7 +781,7 @@ public abstract class MethodVisitor {
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param start
* the fist instructions corresponding to the continuous ranges
* that make the scope of this local variable (inclusive).
@@ -847,16 +795,13 @@ public abstract class MethodVisitor {
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
end, index, desc, visible);
@@ -873,7 +818,7 @@ public abstract class MethodVisitor {
* @param start
* the first instruction corresponding to this line number.
* @throws IllegalArgumentException
* if <tt>start</tt> has not already been visited by this
* if &#60;tt&#62;start&#60;/tt&#62; has not already been visited by this
* visitor (by the {@link #visitLabel visitLabel} method).
*/
public void visitLineNumber(int line, Label start) {

View File

@@ -0,0 +1,219 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A visitor to visit a Java module. The methods of this class must be called in
* the following order: &#60;tt&#62;visitMainClass&#60;/tt&#62; | ( &#60;tt&#62;visitPackage&#60;/tt&#62; |
* &#60;tt&#62;visitRequire&#60;/tt&#62; | &#60;tt&#62;visitExport&#60;/tt&#62; | &#60;tt&#62;visitOpen&#60;/tt&#62; |
* &#60;tt&#62;visitUse&#60;/tt&#62; | &#60;tt&#62;visitProvide&#60;/tt&#62; )* &#60;tt&#62;visitEnd&#60;/tt&#62;.
*
* The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
* {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
* take as parameter a package name or a module name. Unlike the other names which are internal names
* (names separated by slash), module and package names are qualified names (names separated by dot).
*
* @author Remi Forax
*/
public abstract class ModuleVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be {@link Opcodes#ASM6}.
*/
protected final int api;
/**
* The module visitor to which this visitor must delegate method calls. May
* be null.
*/
protected ModuleVisitor mv;
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
*/
public ModuleVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
* @param mv
* the module visitor to which this visitor must delegate method
* calls. May be null.
*/
public ModuleVisitor(final int api, final ModuleVisitor mv) {
if (api != Opcodes.ASM6) {
throw new IllegalArgumentException();
}
this.api = api;
this.mv = mv;
}
/**
* Visit the main class of the current module.
*
* @param mainClass the internal name of the main class of the current module.
*/
public void visitMainClass(String mainClass) {
if (mv != null) {
mv.visitMainClass(mainClass);
}
}
/**
* Visit a package of the current module.
*
* @param packaze the qualified name of a package.
*/
public void visitPackage(String packaze) {
if (mv != null) {
mv.visitPackage(packaze);
}
}
/**
* Visits a dependence of the current module.
*
* @param module the qualified name of the dependence.
* @param access the access flag of the dependence among
* ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC
* and ACC_MANDATED.
* @param version the module version at compile time or null.
*/
public void visitRequire(String module, int access, String version) {
if (mv != null) {
mv.visitRequire(module, access, version);
}
}
/**
* Visit an exported package of the current module.
*
* @param packaze the qualified name of the exported package.
* @param access the access flag of the exported package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can access to
* the public classes of the exported package or
* &#60;tt&#62;null&#60;/tt&#62;.
*/
public void visitExport(String packaze, int access, String... modules) {
if (mv != null) {
mv.visitExport(packaze, access, modules);
}
}
/**
* Visit an open package of the current module.
*
* @param packaze the qualified name of the opened package.
* @param access the access flag of the opened package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can use deep
* reflection to the classes of the open package or
* &#60;tt&#62;null&#60;/tt&#62;.
*/
public void visitOpen(String packaze, int access, String... modules) {
if (mv != null) {
mv.visitOpen(packaze, access, modules);
}
}
/**
* Visit a service used by the current module.
* The name must be the internal name of an interface or a class.
*
* @param service the internal name of the service.
*/
public void visitUse(String service) {
if (mv != null) {
mv.visitUse(service);
}
}
/**
* Visit an implementation of a service.
*
* @param service the internal name of the service
* @param providers the internal names of the implementations
* of the service (there is at least one provider).
*/
public void visitProvide(String service, String... providers) {
if (mv != null) {
mv.visitProvide(service, providers);
}
}
/**
* Visits the end of the module. This method, which is the last one to be
* called, is used to inform the visitor that everything have been visited.
*/
public void visitEnd() {
if (mv != null) {
mv.visitEnd();
}
}
}

View File

@@ -0,0 +1,322 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* @author Remi Forax
*/
final class ModuleWriter extends ModuleVisitor {
/**
* The class writer to which this Module attribute must be added.
*/
private final ClassWriter cw;
/**
* size in byte of the Module attribute.
*/
int size;
/**
* Number of attributes associated with the current module
* (Version, ConcealPackages, etc)
*/
int attributeCount;
/**
* Size in bytes of the attributes associated with the current module
*/
int attributesSize;
/**
* module name index in the constant pool
*/
private final int name;
/**
* module access flags
*/
private final int access;
/**
* module version index in the constant pool or 0
*/
private final int version;
/**
* module main class index in the constant pool or 0
*/
private int mainClass;
/**
* number of packages
*/
private int packageCount;
/**
* The packages in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in packageCount
*/
private ByteVector packages;
/**
* number of requires items
*/
private int requireCount;
/**
* The requires items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in requireCount
*/
private ByteVector requires;
/**
* number of exports items
*/
private int exportCount;
/**
* The exports items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in exportCount
*/
private ByteVector exports;
/**
* number of opens items
*/
private int openCount;
/**
* The opens items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in openCount
*/
private ByteVector opens;
/**
* number of uses items
*/
private int useCount;
/**
* The uses items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in useCount
*/
private ByteVector uses;
/**
* number of provides items
*/
private int provideCount;
/**
* The uses provides in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in provideCount
*/
private ByteVector provides;
ModuleWriter(final ClassWriter cw, final int name,
final int access, final int version) {
super(Opcodes.ASM6);
this.cw = cw;
this.size = 16; // name + access + version + 5 counts
this.name = name;
this.access = access;
this.version = version;
}
@Override
public void visitMainClass(String mainClass) {
if (this.mainClass == 0) { // protect against several calls to visitMainClass
cw.newUTF8("ModuleMainClass");
attributeCount++;
attributesSize += 8;
}
this.mainClass = cw.newClass(mainClass);
}
@Override
public void visitPackage(String packaze) {
if (packages == null) {
// protect against several calls to visitPackage
cw.newUTF8("ModulePackages");
packages = new ByteVector();
attributeCount++;
attributesSize += 8;
}
packages.putShort(cw.newPackage(packaze));
packageCount++;
attributesSize += 2;
}
@Override
public void visitRequire(String module, int access, String version) {
if (requires == null) {
requires = new ByteVector();
}
requires.putShort(cw.newModule(module))
.putShort(access)
.putShort(version == null? 0: cw.newUTF8(version));
requireCount++;
size += 6;
}
@Override
public void visitExport(String packaze, int access, String... modules) {
if (exports == null) {
exports = new ByteVector();
}
exports.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) {
exports.putShort(0);
size += 6;
} else {
exports.putShort(modules.length);
for(String module: modules) {
exports.putShort(cw.newModule(module));
}
size += 6 + 2 * modules.length;
}
exportCount++;
}
@Override
public void visitOpen(String packaze, int access, String... modules) {
if (opens == null) {
opens = new ByteVector();
}
opens.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) {
opens.putShort(0);
size += 6;
} else {
opens.putShort(modules.length);
for(String module: modules) {
opens.putShort(cw.newModule(module));
}
size += 6 + 2 * modules.length;
}
openCount++;
}
@Override
public void visitUse(String service) {
if (uses == null) {
uses = new ByteVector();
}
uses.putShort(cw.newClass(service));
useCount++;
size += 2;
}
@Override
public void visitProvide(String service, String... providers) {
if (provides == null) {
provides = new ByteVector();
}
provides.putShort(cw.newClass(service));
provides.putShort(providers.length);
for(String provider: providers) {
provides.putShort(cw.newClass(provider));
}
provideCount++;
size += 4 + 2 * providers.length;
}
@Override
public void visitEnd() {
// empty
}
void putAttributes(ByteVector out) {
if (mainClass != 0) {
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
}
if (packages != null) {
out.putShort(cw.newUTF8("ModulePackages"))
.putInt(2 + 2 * packageCount)
.putShort(packageCount)
.putByteArray(packages.data, 0, packages.length);
}
}
void put(ByteVector out) {
out.putInt(size);
out.putShort(name).putShort(access).putShort(version);
out.putShort(requireCount);
if (requires != null) {
out.putByteArray(requires.data, 0, requires.length);
}
out.putShort(exportCount);
if (exports != null) {
out.putByteArray(exports.data, 0, exports.length);
}
out.putShort(openCount);
if (opens != null) {
out.putByteArray(opens.data, 0, opens.length);
}
out.putShort(useCount);
if (uses != null) {
out.putByteArray(uses.data, 0, uses.length);
}
out.putShort(provideCount);
if (provides != null) {
out.putByteArray(provides.data, 0, provides.length);
}
}
}

View File

@@ -1,4 +1,33 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
@@ -41,13 +70,12 @@ package org.redkale.asm;
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
@SuppressWarnings("deprecation") // for Integer(int) constructor
public interface Opcodes {
// ASM API versions
int ASM4 = 4 << 16 | 0 << 8 | 0;
int ASM5 = 5 << 16 | 0 << 8 | 0;
int ASM4 = 4 << 16 | 0 << 8;
int ASM5 = 5 << 16 | 0 << 8;
int ASM6 = 6 << 16 | 0 << 8;
// versions
@@ -59,7 +87,9 @@ public interface Opcodes {
int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51;
int V1_8 = 0 << 16 | 52;
int V1_9 = 0 << 16 | 53;
int V9 = 0 << 16 | 53;
int V10 = 0 << 16 | 54;
int V11 = 0 << 16 | 55;
// access flags
@@ -70,18 +100,23 @@ public interface Opcodes {
int ACC_FINAL = 0x0010; // class, field, method, parameter
int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_OPEN = 0x0020; // module
int ACC_TRANSITIVE = 0x0020; // module requires
int ACC_VOLATILE = 0x0040; // field
int ACC_BRIDGE = 0x0040; // method
int ACC_STATIC_PHASE = 0x0040; // module requires
int ACC_VARARGS = 0x0080; // method
int ACC_TRANSIENT = 0x0080; // field
int ACC_NATIVE = 0x0100; // method
int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
int ACC_MANDATED = 0x8000; // parameter
int ACC_MANDATED = 0x8000; // parameter, module, module *
int ACC_MODULE = 0x8000; // class
// ASM specific pseudo access flags
@@ -148,15 +183,17 @@ public interface Opcodes {
*/
int F_SAME1 = 4;
// For reference comparison purposes, construct new instances
// instead of using valueOf() or autoboxing.
Integer TOP = new Integer(0);
Integer INTEGER = new Integer(1);
Integer FLOAT = new Integer(2);
Integer DOUBLE = new Integer(3);
Integer LONG = new Integer(4);
Integer NULL = new Integer(5);
Integer UNINITIALIZED_THIS = new Integer(6);
// Do not try to change the following code to use auto-boxing,
// these values are compared by reference and not by value
// The constructor of Integer was deprecated in 9
// but we are stuck with it by backward compatibility
@SuppressWarnings("deprecation") Integer TOP = new Integer(0);
@SuppressWarnings("deprecation") Integer INTEGER = new Integer(1);
@SuppressWarnings("deprecation") Integer FLOAT = new Integer(2);
@SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3);
@SuppressWarnings("deprecation") Integer LONG = new Integer(4);
@SuppressWarnings("deprecation") Integer NULL = new Integer(5);
@SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6);
// opcodes // visit method (- = idem)

View File

@@ -71,47 +71,47 @@ import java.lang.reflect.Method;
public class Type {
/**
* The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;void&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int VOID = 0;
/**
* The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;boolean&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int BOOLEAN = 1;
/**
* The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;char&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int CHAR = 2;
/**
* The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;byte&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int BYTE = 3;
/**
* The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;short&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int SHORT = 4;
/**
* The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;int&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int INT = 5;
/**
* The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;float&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int FLOAT = 6;
/**
* The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;long&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int LONG = 7;
/**
* The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
* The sort of the &#60;tt&#62;double&#60;/tt&#62; type. See {@link #getSort getSort}.
*/
public static final int DOUBLE = 8;
@@ -131,55 +131,55 @@ public class Type {
public static final int METHOD = 11;
/**
* The <tt>void</tt> type.
* The &#60;tt&#62;void&#60;/tt&#62; type.
*/
public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
| (5 << 16) | (0 << 8) | 0, 1);
/**
* The <tt>boolean</tt> type.
* The &#60;tt&#62;boolean&#60;/tt&#62; type.
*/
public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
| (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>char</tt> type.
* The &#60;tt&#62;char&#60;/tt&#62; type.
*/
public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
| (0 << 16) | (6 << 8) | 1, 1);
/**
* The <tt>byte</tt> type.
* The &#60;tt&#62;byte&#60;/tt&#62; type.
*/
public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
| (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>short</tt> type.
* The &#60;tt&#62;short&#60;/tt&#62; type.
*/
public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
| (0 << 16) | (7 << 8) | 1, 1);
/**
* The <tt>int</tt> type.
* The &#60;tt&#62;int&#60;/tt&#62; type.
*/
public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
| (0 << 16) | (0 << 8) | 1, 1);
/**
* The <tt>float</tt> type.
* The &#60;tt&#62;float&#60;/tt&#62; type.
*/
public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
| (2 << 16) | (2 << 8) | 1, 1);
/**
* The <tt>long</tt> type.
* The &#60;tt&#62;long&#60;/tt&#62; type.
*/
public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
| (1 << 16) | (1 << 8) | 2, 1);
/**
* The <tt>double</tt> type.
* The &#60;tt&#62;double&#60;/tt&#62; type.
*/
public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
| (3 << 16) | (3 << 8) | 2, 1);
@@ -406,7 +406,16 @@ public class Type {
*/
public static Type getReturnType(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray();
return getType(buf, methodDescriptor.indexOf(')') + 1);
int off = 1;
while (true) {
char car = buf[off++];
if (car == ')') {
return getType(buf, off);
} else if (car == 'L') {
while (buf[off++] != ';') {
}
}
}
}
/**
@@ -430,8 +439,8 @@ public class Type {
* @return the size of the arguments of the method (plus one for the
* implicit this argument), argSize, and the size of its return
* value, retSize, packed into a single int i =
* <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
* <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
* &#60;tt&#62;(argSize &lt;&lt; 2) | retSize&#60;/tt&#62; (argSize is therefore equal to
* &#60;tt&#62;i &gt;&gt; 2&#60;/tt&#62;, and retSize to &#60;tt&#62;i &amp; 0x03&#60;/tt&#62;).
*/
public static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
@@ -636,9 +645,9 @@ public class Type {
* @return the size of the arguments (plus one for the implicit this
* argument), argSize, and the size of the return value, retSize,
* packed into a single
* int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
* (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
* and retSize to <tt>i &amp; 0x03</tt>).
* int i = &#60;tt&#62;(argSize &lt;&lt; 2) | retSize&#60;/tt&#62;
* (argSize is therefore equal to &#60;tt&#62;i &gt;&gt; 2&#60;/tt&#62;,
* and retSize to &#60;tt&#62;i &amp; 0x03&#60;/tt&#62;).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
@@ -829,8 +838,8 @@ public class Type {
* Returns the size of values of this type. This method must not be used for
* method types.
*
* @return the size of values of this type, i.e., 2 for <tt>long</tt> and
* <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
* @return the size of values of this type, i.e., 2 for &#60;tt&#62;long&#60;/tt&#62; and
* &#60;tt&#62;double&#60;/tt&#62;, 0 for &#60;tt&#62;void&#60;/tt&#62; and 1 otherwise.
*/
public int getSize() {
// the size is in byte 0 of 'off' for primitive types (buf == null)
@@ -846,8 +855,8 @@ public class Type {
* ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
* ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
* @return an opcode that is similar to the given opcode, but adapted to
* this Java type. For example, if this type is <tt>float</tt> and
* <tt>opcode</tt> is IRETURN, this method returns FRETURN.
* this Java type. For example, if this type is &#60;tt&#62;float&#60;/tt&#62; and
* &#60;tt&#62;opcode&#60;/tt&#62; is IRETURN, this method returns FRETURN.
*/
public int getOpcode(final int opcode) {
if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
@@ -870,7 +879,7 @@ public class Type {
*
* @param o
* the object to be compared to this type.
* @return <tt>true</tt> if the given object is equal to this type.
* @return &#60;tt&#62;true&#60;/tt&#62; if the given object is equal to this type.
*/
@Override
public boolean equals(final Object o) {

View File

@@ -161,7 +161,7 @@ public class TypePath {
* @return the corresponding TypePath object, or null if the path is empty.
*/
public static TypePath fromString(final String typePath) {
if (typePath == null || typePath.length() == 0) {
if (typePath == null || typePath.isEmpty()) {
return null;
}
int n = typePath.length();

View File

@@ -1,427 +1,481 @@
/*
* 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.asm;
/**
* A reference to a type appearing in a class, field or method declaration, or
* on an instruction. Such a reference designates the part of the class where
* the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
* clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
* declaration, etc).
*
* @author Eric Bruneton
*/
public class TypeReference {
/**
* The sort of type references that target a type parameter of a generic
* class. See {@link #getSort getSort}.
*/
public final static int CLASS_TYPE_PARAMETER = 0x00;
/**
* The sort of type references that target a type parameter of a generic
* method. See {@link #getSort getSort}.
*/
public final static int METHOD_TYPE_PARAMETER = 0x01;
/**
* The sort of type references that target the super class of a class or one
* of the interfaces it implements. See {@link #getSort getSort}.
*/
public final static int CLASS_EXTENDS = 0x10;
/**
* The sort of type references that target a bound of a type parameter of a
* generic class. See {@link #getSort getSort}.
*/
public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
/**
* The sort of type references that target a bound of a type parameter of a
* generic method. See {@link #getSort getSort}.
*/
public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
/**
* The sort of type references that target the type of a field. See
* {@link #getSort getSort}.
*/
public final static int FIELD = 0x13;
/**
* The sort of type references that target the return type of a method. See
* {@link #getSort getSort}.
*/
public final static int METHOD_RETURN = 0x14;
/**
* The sort of type references that target the receiver type of a method.
* See {@link #getSort getSort}.
*/
public final static int METHOD_RECEIVER = 0x15;
/**
* The sort of type references that target the type of a formal parameter of
* a method. See {@link #getSort getSort}.
*/
public final static int METHOD_FORMAL_PARAMETER = 0x16;
/**
* The sort of type references that target the type of an exception declared
* in the throws clause of a method. See {@link #getSort getSort}.
*/
public final static int THROWS = 0x17;
/**
* The sort of type references that target the type of a local variable in a
* method. See {@link #getSort getSort}.
*/
public final static int LOCAL_VARIABLE = 0x40;
/**
* The sort of type references that target the type of a resource variable
* in a method. See {@link #getSort getSort}.
*/
public final static int RESOURCE_VARIABLE = 0x41;
/**
* The sort of type references that target the type of the exception of a
* 'catch' clause in a method. See {@link #getSort getSort}.
*/
public final static int EXCEPTION_PARAMETER = 0x42;
/**
* The sort of type references that target the type declared in an
* 'instanceof' instruction. See {@link #getSort getSort}.
*/
public final static int INSTANCEOF = 0x43;
/**
* The sort of type references that target the type of the object created by
* a 'new' instruction. See {@link #getSort getSort}.
*/
public final static int NEW = 0x44;
/**
* The sort of type references that target the receiver type of a
* constructor reference. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE = 0x45;
/**
* The sort of type references that target the receiver type of a method
* reference. See {@link #getSort getSort}.
*/
public final static int METHOD_REFERENCE = 0x46;
/**
* The sort of type references that target the type declared in an explicit
* or implicit cast instruction. See {@link #getSort getSort}.
*/
public final static int CAST = 0x47;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor call. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
/**
* The sort of type references that target a type parameter of a generic
* method in a method call. See {@link #getSort getSort}.
*/
public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor reference. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
/**
* The sort of type references that target a type parameter of a generic
* method in a method reference. See {@link #getSort getSort}.
*/
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
/**
* The type reference value in Java class file format.
*/
private int value;
/**
* Creates a new TypeReference.
*
* @param typeRef
* the int encoded value of the type reference, as received in a
* visit method related to type annotations, like
* visitTypeAnnotation.
*/
public TypeReference(int typeRef) {
this.value = typeRef;
}
/**
* Returns a type reference of the given sort.
*
* @param sort
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
* @return a type reference of the given sort.
*/
public static TypeReference newTypeReference(int sort) {
return new TypeReference(sort << 24);
}
/**
* Returns a reference to a type parameter of a generic class or method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @return a reference to the given generic class or method type parameter.
*/
public static TypeReference newTypeParameterReference(int sort,
int paramIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16));
}
/**
* Returns a reference to a type parameter bound of a generic class or
* method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @param boundIndex
* the type bound index within the above type parameters.
* @return a reference to the given generic class or method type parameter
* bound.
*/
public static TypeReference newTypeParameterBoundReference(int sort,
int paramIndex, int boundIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16)
| (boundIndex << 8));
}
/**
* Returns a reference to the super class or to an interface of the
* 'implements' clause of a class.
*
* @param itfIndex
* the index of an interface in the 'implements' clause of a
* class, or -1 to reference the super class of the class.
* @return a reference to the given super type of a class.
*/
public static TypeReference newSuperTypeReference(int itfIndex) {
itfIndex &= 0xFFFF;
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
}
/**
* Returns a reference to the type of a formal parameter of a method.
*
* @param paramIndex
* the formal parameter index.
*
* @return a reference to the type of the given method formal parameter.
*/
public static TypeReference newFormalParameterReference(int paramIndex) {
return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
| (paramIndex << 16));
}
/**
* Returns a reference to the type of an exception, in a 'throws' clause of
* a method.
*
* @param exceptionIndex
* the index of an exception in a 'throws' clause of a method.
*
* @return a reference to the type of the given exception.
*/
public static TypeReference newExceptionReference(int exceptionIndex) {
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
}
/**
* Returns a reference to the type of the exception declared in a 'catch'
* clause of a method.
*
* @param tryCatchBlockIndex
* the index of a try catch block (using the order in which they
* are visited with visitTryCatchBlock).
*
* @return a reference to the type of the given exception.
*/
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
return new TypeReference((EXCEPTION_PARAMETER << 24)
| (tryCatchBlockIndex << 8));
}
/**
* Returns a reference to the type of a type argument in a constructor or
* method call or reference.
*
* @param sort
* {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
* @param argIndex
* the type argument index.
*
* @return a reference to the type of the given type argument.
*/
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
return new TypeReference((sort << 24) | argIndex);
}
/**
* Returns the sort of this type reference.
*
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_EXTENDS CLASS_EXTENDS},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
* {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
*/
public int getSort() {
return value >>> 24;
}
/**
* Returns the index of the type parameter referenced by this type
* reference. This method must only be used for type references whose sort
* is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter index.
*/
public int getTypeParameterIndex() {
return (value & 0x00FF0000) >> 16;
}
/**
* Returns the index of the type parameter bound, within the type parameter
* {@link #getTypeParameterIndex}, referenced by this type reference. This
* method must only be used for type references whose sort is
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter bound index.
*/
public int getTypeParameterBoundIndex() {
return (value & 0x0000FF00) >> 8;
}
/**
* Returns the index of the "super type" of a class that is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
*
* @return the index of an interface in the 'implements' clause of a class,
* or -1 if this type reference references the type of the super
* class.
*/
public int getSuperTypeIndex() {
return (short) ((value & 0x00FFFF00) >> 8);
}
/**
* Returns the index of the formal parameter whose type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
*
* @return a formal parameter index.
*/
public int getFormalParameterIndex() {
return (value & 0x00FF0000) >> 16;
}
/**
* Returns the index of the exception, in a 'throws' clause of a method,
* whose type is referenced by this type reference. This method must only be
* used for type references whose sort is {@link #THROWS THROWS}.
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getExceptionIndex() {
return (value & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the try catch block (using the order in which they
* are visited with visitTryCatchBlock), whose 'catch' type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getTryCatchBlockIndex() {
return (value & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the type argument referenced by this type reference.
* This method must only be used for type references whose sort is
* {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
*
* @return a type parameter index.
*/
public int getTypeArgumentIndex() {
return value & 0xFF;
}
/**
* Returns the int encoded value of this type reference, suitable for use in
* visit methods related to type annotations, like visitTypeAnnotation.
*
* @return the int encoded value of this type reference.
*/
public int getValue() {
return value;
}
}
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2013 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A reference to a type appearing in a class, field or method declaration, or
* on an instruction. Such a reference designates the part of the class where
* the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
* clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
* declaration, etc).
*
* @author Eric Bruneton
*/
public class TypeReference {
/**
* The sort of type references that target a type parameter of a generic
* class. See {@link #getSort getSort}.
*/
public final static int CLASS_TYPE_PARAMETER = 0x00;
/**
* The sort of type references that target a type parameter of a generic
* method. See {@link #getSort getSort}.
*/
public final static int METHOD_TYPE_PARAMETER = 0x01;
/**
* The sort of type references that target the super class of a class or one
* of the interfaces it implements. See {@link #getSort getSort}.
*/
public final static int CLASS_EXTENDS = 0x10;
/**
* The sort of type references that target a bound of a type parameter of a
* generic class. See {@link #getSort getSort}.
*/
public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
/**
* The sort of type references that target a bound of a type parameter of a
* generic method. See {@link #getSort getSort}.
*/
public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
/**
* The sort of type references that target the type of a field. See
* {@link #getSort getSort}.
*/
public final static int FIELD = 0x13;
/**
* The sort of type references that target the return type of a method. See
* {@link #getSort getSort}.
*/
public final static int METHOD_RETURN = 0x14;
/**
* The sort of type references that target the receiver type of a method.
* See {@link #getSort getSort}.
*/
public final static int METHOD_RECEIVER = 0x15;
/**
* The sort of type references that target the type of a formal parameter of
* a method. See {@link #getSort getSort}.
*/
public final static int METHOD_FORMAL_PARAMETER = 0x16;
/**
* The sort of type references that target the type of an exception declared
* in the throws clause of a method. See {@link #getSort getSort}.
*/
public final static int THROWS = 0x17;
/**
* The sort of type references that target the type of a local variable in a
* method. See {@link #getSort getSort}.
*/
public final static int LOCAL_VARIABLE = 0x40;
/**
* The sort of type references that target the type of a resource variable
* in a method. See {@link #getSort getSort}.
*/
public final static int RESOURCE_VARIABLE = 0x41;
/**
* The sort of type references that target the type of the exception of a
* 'catch' clause in a method. See {@link #getSort getSort}.
*/
public final static int EXCEPTION_PARAMETER = 0x42;
/**
* The sort of type references that target the type declared in an
* 'instanceof' instruction. See {@link #getSort getSort}.
*/
public final static int INSTANCEOF = 0x43;
/**
* The sort of type references that target the type of the object created by
* a 'new' instruction. See {@link #getSort getSort}.
*/
public final static int NEW = 0x44;
/**
* The sort of type references that target the receiver type of a
* constructor reference. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE = 0x45;
/**
* The sort of type references that target the receiver type of a method
* reference. See {@link #getSort getSort}.
*/
public final static int METHOD_REFERENCE = 0x46;
/**
* The sort of type references that target the type declared in an explicit
* or implicit cast instruction. See {@link #getSort getSort}.
*/
public final static int CAST = 0x47;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor call. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
/**
* The sort of type references that target a type parameter of a generic
* method in a method call. See {@link #getSort getSort}.
*/
public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor reference. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
/**
* The sort of type references that target a type parameter of a generic
* method in a method reference. See {@link #getSort getSort}.
*/
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
/**
* The type reference value in Java class file format.
*/
private int value;
/**
* Creates a new TypeReference.
*
* @param typeRef
* the int encoded value of the type reference, as received in a
* visit method related to type annotations, like
* visitTypeAnnotation.
*/
public TypeReference(int typeRef) {
this.value = typeRef;
}
/**
* Returns a type reference of the given sort.
*
* @param sort
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
* @return a type reference of the given sort.
*/
public static TypeReference newTypeReference(int sort) {
return new TypeReference(sort << 24);
}
/**
* Returns a reference to a type parameter of a generic class or method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @return a reference to the given generic class or method type parameter.
*/
public static TypeReference newTypeParameterReference(int sort,
int paramIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16));
}
/**
* Returns a reference to a type parameter bound of a generic class or
* method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @param boundIndex
* the type bound index within the above type parameters.
* @return a reference to the given generic class or method type parameter
* bound.
*/
public static TypeReference newTypeParameterBoundReference(int sort,
int paramIndex, int boundIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16)
| (boundIndex << 8));
}
/**
* Returns a reference to the super class or to an interface of the
* 'implements' clause of a class.
*
* @param itfIndex
* the index of an interface in the 'implements' clause of a
* class, or -1 to reference the super class of the class.
* @return a reference to the given super type of a class.
*/
public static TypeReference newSuperTypeReference(int itfIndex) {
itfIndex &= 0xFFFF;
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
}
/**
* Returns a reference to the type of a formal parameter of a method.
*
* @param paramIndex
* the formal parameter index.
*
* @return a reference to the type of the given method formal parameter.
*/
public static TypeReference newFormalParameterReference(int paramIndex) {
return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
| (paramIndex << 16));
}
/**
* Returns a reference to the type of an exception, in a 'throws' clause of
* a method.
*
* @param exceptionIndex
* the index of an exception in a 'throws' clause of a method.
*
* @return a reference to the type of the given exception.
*/
public static TypeReference newExceptionReference(int exceptionIndex) {
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
}
/**
* Returns a reference to the type of the exception declared in a 'catch'
* clause of a method.
*
* @param tryCatchBlockIndex
* the index of a try catch block (using the order in which they
* are visited with visitTryCatchBlock).
*
* @return a reference to the type of the given exception.
*/
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
return new TypeReference((EXCEPTION_PARAMETER << 24)
| (tryCatchBlockIndex << 8));
}
/**
* Returns a reference to the type of a type argument in a constructor or
* method call or reference.
*
* @param sort
* {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
* @param argIndex
* the type argument index.
*
* @return a reference to the type of the given type argument.
*/
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
return new TypeReference((sort << 24) | argIndex);
}
/**
* Returns the sort of this type reference.
*
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_EXTENDS CLASS_EXTENDS},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
* {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
*/
public int getSort() {
return value >>> 24;
}
/**
* Returns the index of the type parameter referenced by this type
* reference. This method must only be used for type references whose sort
* is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter index.
*/
public int getTypeParameterIndex() {
return (value & 0x00FF0000) >> 16;
}
/**
* Returns the index of the type parameter bound, within the type parameter
* {@link #getTypeParameterIndex}, referenced by this type reference. This
* method must only be used for type references whose sort is
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter bound index.
*/
public int getTypeParameterBoundIndex() {
return (value & 0x0000FF00) >> 8;
}
/**
* Returns the index of the "super type" of a class that is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
*
* @return the index of an interface in the 'implements' clause of a class,
* or -1 if this type reference references the type of the super
* class.
*/
public int getSuperTypeIndex() {
return (short) ((value & 0x00FFFF00) >> 8);
}
/**
* Returns the index of the formal parameter whose type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
*
* @return a formal parameter index.
*/
public int getFormalParameterIndex() {
return (value & 0x00FF0000) >> 16;
}
/**
* Returns the index of the exception, in a 'throws' clause of a method,
* whose type is referenced by this type reference. This method must only be
* used for type references whose sort is {@link #THROWS THROWS}.
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getExceptionIndex() {
return (value & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the try catch block (using the order in which they
* are visited with visitTryCatchBlock), whose 'catch' type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getTryCatchBlockIndex() {
return (value & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the type argument referenced by this type reference.
* This method must only be used for type references whose sort is
* {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
*
* @return a type parameter index.
*/
public int getTypeArgumentIndex() {
return value & 0xFF;
}
/**
* Returns the int encoded value of this type reference, suitable for use in
* visit methods related to type annotations, like visitTypeAnnotation.
*
* @return the int encoded value of this type reference.
*/
public int getValue() {
return value;
}
}

View File

@@ -0,0 +1,535 @@
/*
* 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.io.*;
import java.lang.reflect.*;
import java.math.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import javax.persistence.*;
import org.redkale.convert.*;
import org.redkale.convert.json.*;
import org.redkale.mq.MessageMultiConsumer;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* API接口文档生成类作用生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
* 继承 HttpBaseServlet 是为了获取 HttpMapping 信息 <br>
* https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public final class ApiDocsService {
private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken<RetResult<Object>>() {
}.getType();
private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken<RetResult<String>>() {
}.getType();
private static final java.lang.reflect.Type TYPE_RETRESULT_INTEGER = new TypeToken<RetResult<Integer>>() {
}.getType();
private static final java.lang.reflect.Type TYPE_RETRESULT_LONG = new TypeToken<RetResult<Long>>() {
}.getType();
private final Application app; //Application全局对象
public ApiDocsService(Application app) {
this.app = app;
}
public void run(String[] args) throws Exception {
//是否跳过RPC接口
final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false");
List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
__prefix.setAccessible(true);
Map<String, Map<String, Map<String, Object>>> typesMap = new LinkedHashMap<>();
//https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
Map<String, Object> swaggerPathsMap = new LinkedHashMap<>();
List<Map> swaggerServers = new ArrayList<>();
List<Map> swaggerTags = new ArrayList<>();
Map<String, Map<String, Object>> swaggerComponentsMap = new LinkedHashMap<>();
for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue;
final Map<String, Object> map = new LinkedHashMap<>();
serverList.add(map);
HttpServer server = node.getServer();
map.put("address", server.getSocketAddress());
swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort()));
List<Map<String, Object>> servletsList = new ArrayList<>();
map.put("servlets", servletsList);
String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType;
if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json";
if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';'));
for (HttpServlet servlet : server.getPrepareServlet().getServlets()) {
if (!(servlet instanceof HttpServlet)) continue;
if (servlet instanceof WebSocketServlet) continue;
if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) {
node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer");
continue;
}
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws == null) {
node.logger.log(Level.WARNING, servlet + " not found @WebServlet");
continue;
}
if (ws.name().isEmpty()) {
node.logger.log(Level.INFO, servlet + " be skipped because @WebServlet.name is empty");
continue;
}
final String tag = ws.name().isEmpty() ? servlet.getClass().getSimpleName().replace("Servlet", "").toLowerCase() : ws.name();
final Map<String, Object> servletMap = new LinkedHashMap<>();
String prefix = (String) __prefix.get(servlet);
String[] urlregs = ws.value();
if (prefix != null && !prefix.isEmpty()) {
for (int i = 0; i < urlregs.length; i++) {
urlregs[i] = prefix + urlregs[i];
}
}
servletMap.put("urlregs", urlregs);
servletMap.put("moduleid", ws.moduleid());
servletMap.put("name", ws.name());
servletMap.put("comment", ws.comment());
List<Map> mappingsList = new ArrayList<>();
servletMap.put("mappings", mappingsList);
final Class selfClz = servlet.getClass();
Class clz = servlet.getClass();
HashSet<String> actionUrls = new HashSet<>();
do {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue;
HttpMapping action = method.getAnnotation(HttpMapping.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
if (actionUrls.contains(action.url())) continue;
if (HttpScope.class.isAssignableFrom(action.result())) continue; //忽略模板引擎的方法
if (action.rpconly() && skipRPC) continue; //不生成RPC接口
final List<Map<String, Object>> swaggerParamsList = new ArrayList<>();
final Map<String, Object> mappingMap = new LinkedHashMap<>();
mappingMap.put("url", prefix + action.url());
actionUrls.add(action.url());
mappingMap.put("auth", action.auth());
mappingMap.put("actionid", action.actionid());
mappingMap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>();
mappingMap.put("params", paramsList);
List<String> results = new ArrayList<>();
Type resultType = action.result();
if (!action.resultref().isEmpty()) {
Field f = servlet.getClass().getDeclaredField(action.resultref());
f.setAccessible(true);
resultType = (Type) f.get(servlet);
}
// for (final Class rtype : action.results()) {
// results.add(rtype.getName());
// if (typesMap.containsKey(rtype.getName())) continue;
// if (rtype.getName().startsWith("java.")) continue;
// if (rtype.getName().startsWith("javax.")) continue;
// final boolean filter = FilterBean.class.isAssignableFrom(rtype);
// final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>();
// Class loop = rtype;
// do {
// if (loop == null || loop.isInterface()) break;
// for (Field field : loop.getDeclaredFields()) {
// if (Modifier.isFinal(field.getModifiers())) continue;
// if (Modifier.isStatic(field.getModifiers())) continue;
//
// Map<String, Object> fieldmap = new LinkedHashMap<>();
// fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
//
// Comment comment = field.getAnnotation(Comment.class);
// Column col = field.getAnnotation(Column.class);
// FilterColumn fc = field.getAnnotation(FilterColumn.class);
// if (comment != null) {
// fieldmap.put("comment", comment.value());
// } else if (col != null) {
// fieldmap.put("comment", col.comment());
// } else if (fc != null) {
// fieldmap.put("comment", fc.comment());
// }
// fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
// fieldmap.put("updatable", (filter || col == null || col.updatable()));
// if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
// if (field.getAnnotation(RestAddress.class) != null) continue;
// }
//
// typeMap.put(field.getName(), fieldmap);
// }
// } while ((loop = loop.getSuperclass()) != Object.class);
// typesMap.put(rtype.getName(), typeMap);
// }
mappingMap.put("results", results);
boolean hasbodyparam = false;
Map<String, Object> swaggerRequestBody = new LinkedHashMap<>();
for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
final Map<String, Object> oldapisParamMap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type();
oldapisParamMap.put("name", param.name());
oldapisParamMap.put("radix", param.radix());
oldapisParamMap.put("type", ptype.getName() + (isarray ? "[]" : ""));
oldapisParamMap.put("style", param.style());
oldapisParamMap.put("comment", param.comment());
oldapisParamMap.put("required", param.required());
paramsList.add(oldapisParamMap);
{
final Map<String, Object> paramSchemaMap = new LinkedHashMap<>();
Type paramGenericType = param.type();
if (!param.typeref().isEmpty()) {
Field f = servlet.getClass().getDeclaredField(param.typeref());
f.setAccessible(true);
paramGenericType = (Type) f.get(servlet);
}
simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true);
if (param.style() == HttpParam.HttpParameterStyle.BODY) {
swaggerRequestBody.put("description", param.comment());
swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap)));
} else {
final Map<String, Object> swaggerParamMap = new LinkedHashMap<>();
swaggerParamMap.put("name", param.name());
swaggerParamMap.put("in", param.style().name().toLowerCase());
swaggerParamMap.put("description", param.comment());
swaggerParamMap.put("required", param.required());
if (param.deprecated()) {
swaggerParamMap.put("deprecated", param.deprecated());
}
//https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameterStyle
swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form");
swaggerParamMap.put("explode", true);
swaggerParamMap.put("schema", paramSchemaMap);
Object example = formatExample(param.example(), param.type(), paramGenericType);
if (example != null) swaggerParamMap.put("example", example);
if (!param.example().isEmpty()) {
swaggerParamMap.put("example", param.example());
}
swaggerParamsList.add(swaggerParamMap);
}
}
if (param.style() == HttpParam.HttpParameterStyle.BODY) hasbodyparam = true;
if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesMap.containsKey(ptype.getName())) continue;
if (ptype.getName().startsWith("java.")) continue;
if (ptype.getName().startsWith("javax.")) continue;
final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>();
Class loop = ptype;
final boolean filter = FilterBean.class.isAssignableFrom(loop);
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Column col = field.getAnnotation(Column.class);
FilterColumn fc = field.getAnnotation(FilterColumn.class);
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
typeMap.put(field.getName(), fieldmap);
}
} while ((loop = loop.getSuperclass()) != Object.class);
typesMap.put(ptype.getName(), typeMap);
}
mappingMap.put("result", action.result().getSimpleName().replace("void", "Object"));
mappingsList.add(mappingMap);
final Map<String, Object> swaggerOperatMap = new LinkedHashMap<>();
swaggerOperatMap.put("tags", new String[]{tag});
swaggerOperatMap.put("operationId", action.name());
if (method.getAnnotation(Deprecated.class) != null) {
swaggerOperatMap.put("deprecated", true);
}
Map<String, Object> respSchemaMap = new LinkedHashMap<>();
simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true);
Map<String, Object> respMap = new LinkedHashMap<>();
respMap.put("schema", respSchemaMap);
Object example = formatExample(action.example(), action.result(), resultType);
if (example != null) swaggerOperatMap.put("example", example);
if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody);
swaggerOperatMap.put("parameters", swaggerParamsList);
String actiondesc = action.comment();
if (action.rpconly()) actiondesc = "[Only for RPC API] " + actiondesc;
swaggerOperatMap.put("responses", Utility.ofMap("200", Utility.ofMap("description", actiondesc, "content", Utility.ofMap("application/json", respMap))));
String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase();
if (m == null) {
m = hasbodyparam || TYPE_RETRESULT_STRING.equals(resultType) || TYPE_RETRESULT_INTEGER.equals(resultType)
|| TYPE_RETRESULT_LONG.equals(resultType) || action.name().contains("create") || action.name().contains("insert")
|| action.name().contains("update") || action.name().contains("delete") || action.name().contains("send") ? "post" : "get";
}
swaggerPathsMap.put(prefix + action.url(), Utility.ofMap("description", action.comment(), m, swaggerOperatMap));
}
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletMap);
if (!actionUrls.isEmpty()) swaggerTags.add(Utility.ofMap("name", tag, "description", ws.comment()));
}
servletsList.sort((o1, o2) -> {
String[] urlregs1 = (String[]) o1.get("urlregs");
String[] urlregs2 = (String[]) o2.get("urlregs");
return urlregs1.length > 0 ? (urlregs2.length > 0 ? urlregs1[0].compareTo(urlregs2[0]) : 1) : -1;
});
}
{ // https://github.com/OAI/OpenAPI-Specification
Map<String, Object> swaggerResultMap = new LinkedHashMap<>();
swaggerResultMap.put("openapi", "3.0.0");
Map<String, Object> infomap = new LinkedHashMap<>();
infomap.put("title", "Redkale generate apidoc");
infomap.put("version", "1.0.0");
swaggerResultMap.put("info", infomap);
swaggerResultMap.put("servers", swaggerServers);
swaggerResultMap.put("paths", swaggerPathsMap);
swaggerResultMap.put("tags", swaggerTags);
if (!swaggerComponentsMap.isEmpty()) swaggerResultMap.put("components", Utility.ofMap("schemas", swaggerComponentsMap));
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "openapi-doc.json"));
out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8));
out.close();
}
{
Map<String, Object> oldapisResultMap = new LinkedHashMap<>();
oldapisResultMap.put("servers", serverList);
oldapisResultMap.put("types", typesMap);
final String json = JsonConvert.root().convertTo(oldapisResultMap);
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
out.write(json.getBytes(StandardCharsets.UTF_8));
out.close();
File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html");
InputStream in = null;
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);
}
if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html");
String content = Utility.read(in).replace("'${content}'", json);
in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes(StandardCharsets.UTF_8));
outhtml.close();
}
}
private static void simpleSchemaType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType, Map<String, Object> schemaMap, boolean recursive) {
if (type == int.class || type == Integer.class || type == AtomicInteger.class) {
schemaMap.put("type", "integer");
schemaMap.put("format", "int32");
} else if (type == long.class || type == Long.class
|| type == AtomicLong.class || type == LongAdder.class || type == BigInteger.class) {
schemaMap.put("type", "integer");
schemaMap.put("format", "int64");
} else if (type == float.class || type == Float.class) {
schemaMap.put("type", "number");
schemaMap.put("format", "float");
} else if (type == double.class || type == Double.class || type == BigDecimal.class) {
schemaMap.put("type", "number");
schemaMap.put("format", "double");
} else if (type == boolean.class || type == Boolean.class || type == AtomicBoolean.class) {
schemaMap.put("type", "boolean");
} else if (type.isPrimitive() || Number.class.isAssignableFrom(type)) {
schemaMap.put("type", "number");
} else if (type == String.class || CharSequence.class.isAssignableFrom(type)) {
schemaMap.put("type", "string");
} else if (recursive && (type.isArray() || Collection.class.isAssignableFrom(type))) {
schemaMap.put("type", "array");
Map<String, Object> sbumap = new LinkedHashMap<>();
if (type.isArray()) {
simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false);
} else if (genericType instanceof ParameterizedType) {
Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (subpt instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) subpt, subpt, sbumap, false);
} else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false);
} else {
sbumap.put("type", "object");
}
} else {
sbumap.put("type", "object");
}
schemaMap.put("items", sbumap);
} else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) {
String ct = simpleComponentType(logger, componentsMap, type, genericType);
if (ct == null) {
schemaMap.put("type", "object");
} else {
schemaMap.put("$ref", "#/components/schemas/" + ct);
}
} else {
schemaMap.put("type", "object");
}
}
private static String simpleComponentType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType) {
try {
Encodeable encodeable = JsonFactory.root().loadEncoder(genericType);
String ct = componentKey(logger, componentsMap, null, encodeable, true);
if (ct == null || ct.length() == 0) return null;
if (componentsMap.containsKey(ct)) return ct;
Map<String, Object> cmap = new LinkedHashMap<>();
componentsMap.put(ct, cmap); //必须在调用simpleSchemaType之前put不然嵌套情况下死循环
cmap.put("type", "object");
List<String> requireds = new ArrayList<>();
Map<String, Object> properties = new LinkedHashMap<>();
if (encodeable instanceof ObjectEncoder) {
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
Map<String, Object> schemaMap = new LinkedHashMap<>();
simpleSchemaType(logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true);
String desc = "";
if (member.getField() != null) {
Column col = member.getField().getAnnotation(Column.class);
if (col == null) {
FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class);
if (fcol != null) {
desc = fcol.comment();
if (fcol.required()) requireds.add(member.getAttribute().field());
}
} else {
desc = col.comment();
if (!col.nullable()) requireds.add(member.getAttribute().field());
}
if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) {
desc = member.getField().getAnnotation(Comment.class).value();
}
} else if (member.getMethod() != null) {
Column col = member.getMethod().getAnnotation(Column.class);
if (col == null) {
FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class);
if (fcol != null) {
desc = fcol.comment();
if (fcol.required()) requireds.add(member.getAttribute().field());
}
} else {
desc = col.comment();
if (!col.nullable()) requireds.add(member.getAttribute().field());
}
if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) {
desc = member.getMethod().getAnnotation(Comment.class).value();
}
}
if (!desc.isEmpty()) schemaMap.put("description", desc);
properties.put(member.getAttribute().field(), schemaMap);
}
}
if (!requireds.isEmpty()) cmap.put("required", requireds);
cmap.put("properties", properties);
return ct;
} catch (Exception e) {
logger.log(Level.WARNING, genericType + " generate component info error", e);
return null;
}
}
private static String componentKey(Logger logger, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) {
if (encodeable instanceof ObjectEncoder) {
StringBuilder sb = new StringBuilder();
sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName());
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
if (member.getEncoder() instanceof ArrayEncoder
|| member.getEncoder() instanceof CollectionEncoder) {
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null;
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue;
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb);
} else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) {
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue;
if (member.getEncoder() instanceof SimpledCoder) {
simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
} else {
simpleSchemaType(logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
}
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue;
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb);
} else if (member.getEncoder() instanceof MapEncoder) {
continue;
} else {
return null;
}
}
return sb.toString();
} else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) {
final boolean array = (encodeable instanceof ArrayEncoder);
Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder();
if (subEncodeable instanceof SimpledCoder && field != null) return "";
final String sb = componentKey(logger, componentsMap, null, subEncodeable, false);
if (sb == null || sb.isEmpty()) return sb;
if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) {
return sb;
}
return sb + (array ? "_Array" : "_Collection");
} else if (encodeable instanceof SimpledCoder) {
Class stype = ((SimpledCoder) encodeable).getType();
if (stype.isPrimitive() || stype == Boolean.class || Number.class.isAssignableFrom(stype) || CharSequence.class.isAssignableFrom(stype)) {
return stype.getSimpleName();
}
return "";
} else if (encodeable instanceof MapEncoder) {
return first ? null : "";
} else {
return null;
}
}
private static Object formatExample(String example, Class type, Type genericType) {
if (example == null || example.isEmpty()) return null;
if (type == Flipper.class) {
return new Flipper();
} else if (TYPE_RETRESULT_OBJECT.equals(genericType)) {
return RetResult.success();
} else if (TYPE_RETRESULT_STRING.equals(genericType)) {
return RetResult.success();
} else if (TYPE_RETRESULT_INTEGER.equals(genericType)) {
return RetResult.success(0);
} else if (TYPE_RETRESULT_LONG.equals(genericType)) {
return RetResult.success(0L);
}
return example;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,30 @@ public interface ApplicationListener {
default void preStart(Application application) {
}
/**
* Application 在运行start后调用
*
* @param application Application
*/
default void postStart(Application application) {
}
/**
* Application 在运行Compile前调用
*
* @param application Application
*/
default void preCompile(Application application) {
}
/**
* Application 在运行Compile后调用
*
* @param application Application
*/
default void postCompile(Application application) {
}
/**
* Application 在运行shutdown前调用
*

View File

@@ -7,10 +7,12 @@ package org.redkale.boot;
import java.io.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.lang.reflect.Modifier;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Predicate;
import java.util.jar.*;
import java.util.logging.*;
import java.util.regex.*;
@@ -30,12 +32,14 @@ public final class ClassFilter<T> {
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
private static final boolean finer = logger.isLoggable(Level.FINER); //日志级别
private static final boolean finest = logger.isLoggable(Level.FINEST); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
private Predicate<String> expectPredicate;
private boolean refused; //是否拒绝所有数据,设置true则其他规则失效,都是拒绝.
private Class superClass; //符合的父类型不为空时扫描结果的class必须是superClass的子类
@@ -60,11 +64,11 @@ public final class ClassFilter<T> {
private final ClassLoader classLoader;
public ClassFilter(ClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses) {
public ClassFilter(RedkaleClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses) {
this(classLoader, annotationClass, superClass, excludeSuperClasses, null);
}
public ClassFilter(ClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) {
public ClassFilter(RedkaleClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) {
this.annotationClass = annotationClass;
this.superClass = superClass;
this.excludeSuperClasses = excludeSuperClasses;
@@ -72,8 +76,8 @@ public final class ClassFilter<T> {
this.classLoader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
}
public static ClassFilter create(Class[] excludeSuperClasses, String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
ClassFilter filter = new ClassFilter(null, null, null, excludeSuperClasses);
public static ClassFilter create(RedkaleClassLoader classLoader, Class[] excludeSuperClasses, String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
ClassFilter filter = new ClassFilter(classLoader, null, null, excludeSuperClasses);
filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";"));
filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";"));
filter.setPrivilegeIncludes(includeValues);
@@ -136,10 +140,11 @@ public final class ClassFilter<T> {
*
* @param property AnyValue
* @param clazzname String
* @param url URL
*/
@SuppressWarnings("unchecked")
public final void filter(AnyValue property, String clazzname) {
filter(property, clazzname, true);
public final void filter(AnyValue property, String clazzname, URL url) {
filter(property, clazzname, true, url);
}
/**
@@ -150,6 +155,18 @@ public final class ClassFilter<T> {
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
*/
public final void filter(AnyValue property, String clazzname, boolean autoscan) {
filter(property, clazzname, autoscan, null);
}
/**
* 过滤指定的class
*
* @param property application.xml中对应class节点下的property属性项
* @param clazzname class名称
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
* @param url URL
*/
public final void filter(AnyValue property, String clazzname, boolean autoscan, URL url) {
boolean r = accept0(property, clazzname);
ClassFilter cf = r ? this : null;
if (r && ands != null) {
@@ -159,13 +176,14 @@ public final class ClassFilter<T> {
}
if (!r && ors != null) {
for (ClassFilter filter : ors) {
if (filter.accept(property, clazzname)) {
if (filter.accept(filter.conf, clazzname)) {
cf = filter;
property = cf.conf;
break;
}
}
}
if (cf == null || clazzname.startsWith("sun.")) return;
if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) return;
try {
Class clazz = classLoader.loadClass(clazzname);
if (!cf.accept(property, clazz, autoscan)) return;
@@ -173,25 +191,28 @@ public final class ClassFilter<T> {
if (property == null) {
property = cf.conf;
} else if (property instanceof DefaultAnyValue) {
((DefaultAnyValue) property).addAll(cf.conf);
((DefaultAnyValue) property).addAllStringSet(cf.conf);
} else {
DefaultAnyValue dav = new DefaultAnyValue();
dav.addAll(property);
dav.addAll(cf.conf);
dav.addAllStringSet(property);
dav.addAllStringSet(cf.conf);
property = dav;
}
}
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
} else {
entrys.add(new FilterEntry(clazz, autoscan, false, property));
}
} catch (Throwable cfe) {
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) {
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe);
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
&& !clazzname.startsWith("com.mysql.") && !clazzname.startsWith("com.microsoft.") && !clazzname.startsWith("freemarker.")
&& !clazzname.startsWith("org.redkale") && (clazzname.contains("Service") || clazzname.contains("Servlet"))) {
//&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) {
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe);
}
}
}
@@ -224,7 +245,7 @@ public final class ClassFilter<T> {
}
if (!r && ors != null) {
for (ClassFilter filter : ors) {
if (filter.accept(property, classname)) return true;
if (filter.accept(filter.conf, classname)) return true;
}
}
return r;
@@ -333,6 +354,14 @@ public final class ClassFilter<T> {
this.refused = refused;
}
public Predicate<String> getExpectPredicate() {
return expectPredicate;
}
public void setExpectPredicate(Predicate<String> predicate) {
this.expectPredicate = predicate;
}
public Set<String> getPrivilegeIncludes() {
return privilegeIncludes;
}
@@ -347,6 +376,7 @@ public final class ClassFilter<T> {
public void setPrivilegeExcludes(Set<String> privilegeExcludes) {
this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes;
}
/**
@@ -379,7 +409,7 @@ public final class ClassFilter<T> {
str = str.trim();
if (str.endsWith(";")) str = str.substring(0, str.length() - 1);
}
if (str != null) groups.addAll(Arrays.asList(str.split(";")));
if (str != null) this.groups.addAll(Arrays.asList(str.split(";")));
this.property = property;
this.autoload = autoload;
this.expect = expect;
@@ -389,7 +419,7 @@ public final class ClassFilter<T> {
@Override
public String toString() {
return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName()
+ ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + groups + "]";
+ ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + this.groups + "]";
}
@Override
@@ -416,6 +446,10 @@ public final class ClassFilter<T> {
return property;
}
public boolean containsGroup(String group) {
return groups != null && groups.contains(group);
}
public boolean isEmptyGroups() {
return groups == null || groups.isEmpty();
}
@@ -450,24 +484,24 @@ public final class ClassFilter<T> {
* 加载当前线程的classpath扫描所有class进行过滤
*
* @param excludeFile 不需要扫描的文件夹 可以为null
* @param loader RedkaleClassloader 不可为null
* @param excludeRegs 包含此关键字的文件将被跳过 可以为null
* @param filters 过滤器
*
* @throws IOException 异常
*/
public static void load(final File excludeFile, final String[] excludeRegs, final ClassFilter... filters) throws IOException {
RedkaleClassLoader loader = (RedkaleClassLoader) Thread.currentThread().getContextClassLoader();
public static void load(final File excludeFile, RedkaleClassLoader loader, final String[] excludeRegs, final ClassFilter... filters) throws IOException {
List<URL> urlfiles = new ArrayList<>(2);
List<URL> urljares = new ArrayList<>(2);
final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null;
final Pattern[] excludePatterns = toPattern(excludeRegs);
for (URL url : loader.getAllURLs()) {
if (exurl != null && exurl.sameFile(url)) continue;
if (excludePatterns != null) {
if (excludePatterns != null && url != RedkaleClassLoader.URL_NONE) {
boolean skip = false;
for (Pattern p : excludePatterns) {
if (p.matcher(url.toString()).matches()) {
skip = false;
skip = true;
break;
}
}
@@ -486,7 +520,7 @@ public final class ClassFilter<T> {
Set<String> classes = cache.get(url);
if (classes == null) {
classes = new LinkedHashSet<>();
try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), "UTF-8"))) {
try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8))) {
Enumeration<JarEntry> it = jar.entries();
while (it.hasMoreElements()) {
String entryname = it.nextElement().getName().replace('/', '.');
@@ -494,6 +528,7 @@ public final class ClassFilter<T> {
String classname = entryname.substring(0, entryname.length() - 6);
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
//常见的jar跳过
if (classname.startsWith("com.redkaledyn.")) break; //redkale动态生成的类
if (classname.startsWith("com.mysql.")) break;
if (classname.startsWith("org.mariadb.")) break;
if (classname.startsWith("oracle.jdbc.")) break;
@@ -502,7 +537,7 @@ public final class ClassFilter<T> {
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
if (filter != null) filter.filter(null, classname, url);
}
}
}
@@ -511,7 +546,7 @@ public final class ClassFilter<T> {
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
if (filter != null) filter.filter(null, classname, url);
}
}
}
@@ -520,24 +555,34 @@ public final class ClassFilter<T> {
Set<String> classes = cache.get(url);
if (classes == null) {
classes = new LinkedHashSet<>();
files.clear();
File root = new File(url.getFile());
String rootpath = root.getPath();
loadClassFiles(excludeFile, root, files);
for (File f : files) {
String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.');
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
final Set<String> cs = classes;
if (url == RedkaleClassLoader.URL_NONE) loader.forEachCacheClass(v -> cs.add(v));
if (cs.isEmpty()) {
files.clear();
File root = new File(url.getFile());
String rootpath = root.getPath();
loadClassFiles(excludeFile, root, files);
for (File f : files) {
String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.');
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname, url);
}
}
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname, url);
}
}
}
cache.put(url, classes);
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
if (filter != null) filter.filter(null, classname, url);
}
}
}
@@ -550,7 +595,9 @@ public final class ClassFilter<T> {
files.add(root);
} else if (root.isDirectory()) {
if (exclude != null && exclude.equals(root)) return;
for (File f : root.listFiles()) {
File[] lfs = root.listFiles();
if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()");
for (File f : lfs) {
loadClassFiles(exclude, f, files);
}
}

View File

@@ -5,6 +5,8 @@
*/
package org.redkale.boot;
import org.redkale.util.RedkaleClassLoader;
import java.io.*;
import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;
@@ -24,12 +26,15 @@ import java.util.regex.Pattern;
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public class LogFileHandler extends Handler {
public class LoggingFileHandler extends Handler {
//public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n";
public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n";
/**
* SNCP的日志输出Handler
*/
public static class SncpLogFileHandler extends LogFileHandler {
public static class LoggingSncpFileHandler extends LoggingFileHandler {
@Override
public String getPrefix() {
@@ -39,26 +44,25 @@ public class LogFileHandler extends Handler {
/**
* 默认的日志时间格式化类
* 与SimpleFormatter的区别在于level不使用本地化
*
*/
public static class LoggingFormater extends Formatter {
private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n";
@Override
public String format(LogRecord record) {
public String format(LogRecord log) {
String source;
if (record.getSourceClassName() != null) {
source = record.getSourceClassName();
if (record.getSourceMethodName() != null) {
source += " " + record.getSourceMethodName();
if (log.getSourceClassName() != null) {
source = log.getSourceClassName();
if (log.getSourceMethodName() != null) {
source += " " + log.getSourceMethodName();
}
} else {
source = record.getLoggerName();
source = log.getLoggerName();
}
String message = formatMessage(record);
String message = formatMessage(log);
String throwable = "";
if (record.getThrown() != null) {
if (log.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw) {
@Override
@@ -67,22 +71,38 @@ public class LogFileHandler extends Handler {
}
};
pw.println();
record.getThrown().printStackTrace(pw);
log.getThrown().printStackTrace(pw);
pw.close();
throwable = sw.toString();
}
return String.format(format,
return String.format(FORMATTER_FORMAT,
System.currentTimeMillis(),
source,
record.getLoggerName(),
record.getLevel().getName(),
log.getLoggerName(),
log.getLevel().getName(),
message,
throwable);
}
}
protected final LinkedBlockingQueue<LogRecord> records = new LinkedBlockingQueue();
public static void initDebugLogConfig() {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(out);
ps.println("handlers = java.util.logging.ConsoleHandler");
ps.println(".level = FINEST");
ps.println("jdk.level = INFO");
ps.println("sun.level = INFO");
ps.println("com.sun.level = INFO");
ps.println("javax.level = INFO");
ps.println("java.util.logging.ConsoleHandler.level = FINEST");
ps.println("java.util.logging.ConsoleHandler.formatter = " + LoggingFileHandler.LoggingFormater.class.getName());
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (Exception e) {
}
}
protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue();
private String pattern;
@@ -114,7 +134,7 @@ public class LogFileHandler extends Handler {
private OutputStream logunusualstream;
public LogFileHandler() {
public LoggingFileHandler() {
updateTomorrow();
configure();
open();
@@ -133,7 +153,7 @@ public class LogFileHandler extends Handler {
}
private void open() {
final String name = "Logging-" + getClass().getSimpleName() + "-Thread";
final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread";
new Thread() {
{
setName(name);
@@ -144,9 +164,9 @@ public class LogFileHandler extends Handler {
public void run() {
while (true) {
try {
LogRecord record = records.take();
LogRecord log = logqueue.take();
final boolean bigger = (limit > 0 && limit <= loglength.get());
final boolean changeday = tomorrow <= record.getMillis();
final boolean changeday = tomorrow <= log.getMillis();
if (bigger || changeday) {
updateTomorrow();
if (logstream != null) {
@@ -193,12 +213,12 @@ public class LogFileHandler extends Handler {
logunusualstream = new FileOutputStream(logunusualfile, append);
}
//----------------------写日志-------------------------
String message = getFormatter().format(record);
String message = getFormatter().format(log);
String encoding = getEncoding();
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
logstream.write(bytes);
loglength.addAndGet(bytes.length);
if (unusual != null && (record.getLevel() == Level.WARNING || record.getLevel() == Level.SEVERE)) {
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
logunusualstream.write(bytes);
logunusuallength.addAndGet(bytes.length);
}
@@ -218,7 +238,7 @@ public class LogFileHandler extends Handler {
private void configure() {
LogManager manager = LogManager.getLogManager();
String cname = LogFileHandler.class.getName();
String cname = LoggingFileHandler.class.getName();
this.pattern = manager.getProperty(cname + ".pattern");
if (this.pattern == null) {
this.pattern = "logs-%m/" + getPrefix() + "log-%d.log";
@@ -241,7 +261,21 @@ public class LogFileHandler extends Handler {
}
String limitstr = manager.getProperty(cname + ".limit");
try {
if (limitstr != null) this.limit = Math.abs(Integer.decode(limitstr));
if (limitstr != null) {
limitstr = limitstr.toUpperCase();
boolean g = limitstr.indexOf('G') > 0;
boolean m = limitstr.indexOf('M') > 0;
boolean k = limitstr.indexOf('K') > 0;
int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", "")));
if (g) {
ls *= 1024 * 1024 * 1024;
} else if (m) {
ls *= 1024 * 1024;
} else if (k) {
ls *= 1024;
}
this.limit = ls;
}
} catch (Exception e) {
}
String countstr = manager.getProperty(cname + ".count");
@@ -266,7 +300,8 @@ public class LogFileHandler extends Handler {
try {
if (filterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
setFilter((Filter) clz.newInstance());
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
}
} catch (Exception e) {
}
@@ -274,7 +309,8 @@ public class LogFileHandler extends Handler {
try {
if (formatterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
setFormatter((Formatter) clz.newInstance());
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
}
} catch (Exception e) {
}
@@ -296,21 +332,21 @@ public class LogFileHandler extends Handler {
}
@Override
public void publish(LogRecord record) {
final String sourceClassName = record.getSourceClassName();
public void publish(LogRecord log) {
final String sourceClassName = log.getSourceClassName();
if (sourceClassName == null || true) {
StackTraceElement[] ses = new Throwable().getStackTrace();
for (int i = 2; i < ses.length; i++) {
if (ses[i].getClassName().startsWith("java.util.logging")) continue;
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
record.setSourceMethodName(ses[i].getMethodName());
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
log.setSourceMethodName(ses[i].getMethodName());
break;
}
} else {
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
}
if (denyreg != null && denyreg.matcher(record.getMessage()).find()) return;
records.offer(record);
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
logqueue.offer(log);
}
@Override

View File

@@ -1,341 +1,446 @@
/*
* 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 java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.logging.Level;
import javax.annotation.*;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.Sncp;
import org.redkale.service.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
* HTTP Server节点的配置Server
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@NodeProtocol({"HTTP"})
public class NodeHttpServer extends NodeServer {
protected final boolean rest; //是否加载REST服务 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
protected final HttpServer httpServer;
public NodeHttpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.httpServer = (HttpServer) server;
this.rest = serconf == null ? false : serconf.getAnyValue("rest") != null;
}
private static Server createServer(Application application, AnyValue serconf) {
return new HttpServer(application.getStartTime(), application.getResourceFactory().createChild());
}
public HttpServer getHttpServer() {
return httpServer;
}
@Override
public InetSocketAddress 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
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
}
@Override
protected ClassFilter createOtherClassFilter() {
return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
}
@Override
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
super.loadService(serviceFilter, otherFilter);
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() {
final NodeServer self = this;
final ResourceFactory regFactory = application.getResourceFactory();
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
try {
if (field.getAnnotation(Resource.class) == null) 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) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
}
if (nodeService == null) {
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService);
}
resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
field.set(src, nodeService);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
}
}, WebSocketNode.class);
}
@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 String threadName = "[" + Thread.currentThread().getName() + "] ";
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
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
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;
});
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
for (FilterEntry<? extends Servlet> en : list) {
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
WebServlet ws = clazz.getAnnotation(WebServlet.class);
if (ws == null || ws.value().length == 0) continue;
final HttpServlet servlet = clazz.newInstance();
resourceFactory.inject(servlet, this);
final String[] mappings = ws.value();
String pref = ws.repair() ? prefix : "";
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
if (ss != null) {
for (int i = 0; i < mappings.length; i++) {
mappings[i] = pref + mappings[i];
}
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings));
}
}
int max = 0;
if (ss != null && sb != null) {
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
}
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' ');
}
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
}
if (rest && serverConf != null) {
final List<Object> restedObjects = new ArrayList<>();
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
loadRestServlet(webSocketFilter, restConf, restedObjects, sb);
}
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
}
@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 (restConf == null) return; //不存在REST服务
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 List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
final boolean autoload = restConf.getBoolValue("autoload", true);
{ //加载RestService
String userTypeStr = restConf.getValue("usertype");
final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr);
final Class baseServletType = this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName()));
final Set<String> includeValues = new HashSet<>();
final Set<String> excludeValues = new HashSet<>();
for (AnyValue item : restConf.getAnyValues("service")) {
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);
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));
}
}
}
//输出信息
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()));
int max = 0;
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
}
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' ');
}
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
}
}
}
/*
* 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 java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.stream.Stream;
import javax.annotation.*;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.cluster.ClusterAgent;
import org.redkale.mq.MessageAgent;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.Sncp;
import org.redkale.service.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
* HTTP Server节点的配置Server
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@NodeProtocol("HTTP")
public class NodeHttpServer extends NodeServer {
protected final boolean rest; //是否加载REST服务 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
protected final HttpServer httpServer;
public NodeHttpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.httpServer = (HttpServer) server;
this.rest = serconf == null ? false : serconf.getAnyValue("rest") != null;
}
private static Server createServer(Application application, AnyValue serconf) {
return new HttpServer(application, application.getStartTime(), application.getResourceFactory().createChild());
}
public HttpServer getHttpServer() {
return httpServer;
}
@Override
public InetSocketAddress getSocketAddress() {
return httpServer == null ? null : httpServer.getSocketAddress();
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, HttpFilter.class, new Class[]{WatchFilter.class}, null, "filters", "filter");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
}
@Override
protected ClassFilter createOtherClassFilter() {
return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
}
@Override
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
super.loadService(serviceFilter, otherFilter);
initWebSocketService();
}
@Override
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter);
}
@Override
@SuppressWarnings("unchecked")
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpServlet(servletFilter, otherFilter);
}
private void initWebSocketService() {
final NodeServer self = this;
final ResourceFactory regFactory = application.getResourceFactory();
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
try {
if (field.getAnnotation(Resource.class) == null) 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) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
}
if (nodeService == null) {
MessageAgent messageAgent = null;
try {
Field c = WebSocketServlet.class.getDeclaredField("messageAgent");
c.setAccessible(true);
messageAgent = (MessageAgent) c.get(src);
} catch (Exception ex) {
logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex);
}
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService);
}
resourceFactory.inject(nodeService, self);
field.set(src, nodeService);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
}
}, WebSocketNode.class);
}
@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 String localThreadName = "[" + Thread.currentThread().getName() + "] ";
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;
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
final HttpFilter filter = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(filter, this);
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
this.httpServer.addHttpFilter(filter, filterConf);
if (sb != null) sb.append(localThreadName).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 {
RedkaleClassLoader.putReflectionPublicClasses(HttpServlet.class.getName());
RedkaleClassLoader.putReflectionPublicClasses(HttpPrepareServlet.class.getName());
RedkaleClassLoader.putReflectionDeclaredConstructors(HttpResourceServlet.class, HttpResourceServlet.class.getName());
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 localThreadName = "[" + 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
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
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;
});
final long starts = System.currentTimeMillis();
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
for (FilterEntry<? extends Servlet> en : list) {
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
if (clazz.getAnnotation(Rest.RestDyn.class) != null) continue; //动态生成的跳过
WebServlet ws = clazz.getAnnotation(WebServlet.class);
if (ws == null) continue;
if (ws.value().length == 0) {
logger.log(Level.INFO, "not found @WebServlet.value in " + clazz.getName());
continue;
}
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(servlet, this);
final String[] mappings = ws.value();
String pref = ws.repair() ? prefix : "";
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
if (ss != null) {
for (int i = 0; i < mappings.length; i++) {
mappings[i] = pref + mappings[i];
}
ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings));
}
}
final List<AbstractMap.SimpleEntry<String, String[]>> rests = sb == null ? null : new ArrayList<>();
final List<AbstractMap.SimpleEntry<String, String[]>> webss = sb == null ? null : new ArrayList<>();
if (rest && serverConf != null) {
final List<Object> restedObjects = new ArrayList<>();
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
loadRestServlet(webSocketFilter, restConf, restedObjects, sb, rests, webss);
}
}
int max = 0;
if (ss != null && sb != null) {
int maxTypeLength = 0;
int maxNameLength = 0;
if (rests != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
int pos = en.getKey().indexOf('#');
if (pos > maxTypeLength) maxTypeLength = pos;
int len = en.getKey().length() - pos - 1;
if (len > maxNameLength) maxNameLength = len;
}
}
if (webss != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
int pos = en.getKey().indexOf('#');
if (pos > maxTypeLength) maxTypeLength = pos;
int len = en.getKey().length() - pos - 1;
if (len > maxNameLength) maxNameLength = len;
}
}
if (rests != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
StringBuilder sub = new StringBuilder();
int pos = en.getKey().indexOf('#');
sub.append("RestDynServlet (type=").append(en.getKey().substring(0, pos));
for (int i = 0; i < maxTypeLength - pos; i++) {
sub.append(' ');
}
sub.append(", name='").append(en.getKey().substring(pos + 1));
for (int i = 0; i < maxNameLength - pos; i++) {
sub.append(' ');
}
sub.append("')");
ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
}
}
if (webss != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
StringBuilder sub = new StringBuilder();
int pos = en.getKey().indexOf('#');
sub.append("RestWebSocket (type=").append(en.getKey().substring(0, pos));
for (int i = 0; i < maxTypeLength - pos; i++) {
sub.append(' ');
}
sub.append(", name='").append(en.getKey().substring(pos + 1));
for (int i = 0; i < maxNameLength - pos; i++) {
sub.append(' ');
}
sub.append("')");
ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
}
}
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
}
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(localThreadName).append("Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' ');
}
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
sb.append(localThreadName).append("All HttpServlets load cost ").append(System.currentTimeMillis() - starts).append(" ms").append(LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
}
@SuppressWarnings("unchecked")
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, final StringBuilder sb,
final List<AbstractMap.SimpleEntry<String, String[]>> rests, final List<AbstractMap.SimpleEntry<String, String[]>> webss) throws Exception {
if (!rest) return;
if (restConf == null) return; //不存在REST服务
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 localThreadName = "[" + Thread.currentThread().getName() + "] ";
String mqname = restConf.getValue("mq");
MessageAgent agent0 = null;
if (mqname != null) {
agent0 = application.getMessageAgent(mqname);
if (agent0 == null) throw new RuntimeException("not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")");
}
final MessageAgent messageAgent = agent0;
if (messageAgent != null) prefix0 = ""; //开启MQ时,prefix字段失效
final String prefix = prefix0;
final boolean autoload = restConf.getBoolValue("autoload", true);
{ //加载RestService
String userTypeStr = restConf.getValue("usertype");
final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr);
final Class baseServletType = this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName()));
final Set<String> includeValues = new HashSet<>();
final Set<String> excludeValues = new HashSet<>();
for (AnyValue item : restConf.getAnyValues("service")) {
if (item.getBoolValue("ignore", false)) {
excludeValues.add(item.getValue("value", ""));
} else {
includeValues.add(item.getValue("value", ""));
}
}
final ClassFilter restFilter = ClassFilter.create(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : restConf.getValue("excludes", ""), includeValues, excludeValues);
final CountDownLatch scdl = new CountDownLatch(super.interceptorServices.size());
Stream<Service> stream = super.interceptorServices.stream();
if (!application.isCompileMode()) stream = stream.parallel(); //不能并行否则在maven plugin运行环境下ClassLoader不对
stream.forEach((service) -> {
try {
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;
synchronized (restedObjects) {
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);
dynServletMap.put(service, servlet);
if (messageAgent != null) messageAgent.putService(this, service, servlet);
//if (finest) logger.finest(localThreadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (rests != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
synchronized (rests) {
rests.add(new AbstractMap.SimpleEntry<>(Sncp.getServiceType(service).getName() + "#" + name, mappings));
}
}
} finally {
scdl.countDown();
}
});
scdl.await();
}
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(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : 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();
if (stype.getAnnotation(Rest.RestDyn.class) != null) continue;
RestWebSocket rs = stype.getAnnotation(RestWebSocket.class);
if (rs == null || rs.ignore()) continue;
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) continue;
if (!restFilter.accept(stypename)) continue;
if (restedObjects.contains(stype)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore");
continue;
}
restedObjects.add(stype); //避免重复创建Rest对象
WebSocketServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, messageAgent, prefix, en.getProperty());
if (servlet == null) continue; //没有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(localThreadName + " " + stype.getName() + " create a RestWebSocketServlet");
if (webss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
synchronized (webss) {
webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + "#" + rs.name(), mappings));
}
}
}
}
if (messageAgent != null) this.messageAgents.put(messageAgent.getName(), messageAgent);
}
@Override //loadServlet执行之后调用
protected void postLoadServlets() {
final ClusterAgent cluster = application.clusterAgent;
if (!application.isCompileMode() && cluster != null) {
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
String protocol = pros.value().toUpperCase();
if (!cluster.containsProtocol(protocol)) return;
if (!cluster.containsPort(server.getSocketAddress().getPort())) return;
cluster.register(this, protocol, dynServletMap.keySet(), new HashSet<>());
}
}
@Override
protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) {
cluster.deregister(this, protocol, dynServletMap.keySet(), new HashSet<>());
}
}

View File

@@ -20,5 +20,5 @@ import java.lang.annotation.*;
@Documented
public @interface NodeProtocol {
String[] value();
String value();
}

View File

@@ -0,0 +1,910 @@
/*
* 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 org.redkale.cluster.ClusterAgent;
import org.redkale.mq.MessageAgent;
import org.redkale.util.RedkaleClassLoader;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.logging.*;
import javax.annotation.*;
import static org.redkale.boot.Application.*;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.net.Filter;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* Server节点的初始化配置类
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public abstract class NodeServer {
//INFO日志的换行符
public static final String LINE_SEPARATOR = "\r\n";
//日志输出对象
protected final Logger logger;
//进程主类
protected final Application application;
//依赖注入工厂类
protected final ResourceFactory resourceFactory;
//当前Server对象
protected final Server server;
//ClassLoader
protected RedkaleClassLoader serverClassLoader;
protected final Thread serverThread;
//当前Server的SNCP协议的组
protected String sncpGroup = null;
//SNCP服务的地址 非SNCP为null
private InetSocketAddress sncpAddress;
//加载Service时的处理函数
protected BiConsumer<MessageAgent, Service> consumer;
//server节点的配置
protected AnyValue serverConf;
protected final String threadName;
//加载server节点后的拦截器
protected NodeInterceptor interceptor;
//供interceptor使用的Service对象集合
protected final Set<Service> interceptorServices = new LinkedHashSet<>();
//本地模式的Service对象集合
protected final Set<Service> localServices = new LinkedHashSet<>();
//远程模式的Service对象集合
protected final Set<Service> remoteServices = new LinkedHashSet<>();
protected final Map<Service, Servlet> dynServletMap = new LinkedHashMap<>();
//MessageAgent对象集合
protected final Map<String, MessageAgent> messageAgents = new HashMap<>();
//需要远程模式Service的MessageAgent对象集合
protected final Map<String, MessageAgent> sncpRemoteAgents = new HashMap<>();
private volatile int maxTypeLength = 0;
private volatile int maxNameLength = 0;
public NodeServer(Application application, Server server) {
this.threadName = Thread.currentThread().getName();
this.application = application;
this.server = server;
this.resourceFactory = server.getResourceFactory();
this.logger = Logger.getLogger(this.getClass().getSimpleName());
if (application.isCompileMode() || application.getServerClassLoader() instanceof RedkaleClassLoader.RedkaleCacheClassLoader) {
this.serverClassLoader = application.getServerClassLoader();
} else {
this.serverClassLoader = new RedkaleClassLoader(application.getServerClassLoader());
}
Thread.currentThread().setContextClassLoader(this.serverClassLoader);
this.serverThread = Thread.currentThread();
this.server.setServerClassLoader(serverClassLoader);
}
public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) {
try {
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName(), Application.class, AnyValue.class);
return clazz.getDeclaredConstructor(Application.class, AnyValue.class).newInstance(application, serconf);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void init(AnyValue config) throws Exception {
this.serverConf = config == null ? AnyValue.create() : config;
if (isSNCP()) { // SNCP协议
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.getAddress().getHostAddress() : host, this.serverConf.getIntValue("port"));
this.sncpGroup = application.sncpTransportFactory.findGroupName(this.sncpAddress);
//单向SNCP服务不需要对等group
//if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
}
//单点服务不会有 sncpAddress、sncpGroup
if (this.sncpAddress != null) {
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文件夹
String webroot = this.serverConf.getValue("root", "root");
File myroot = new File(webroot);
if (!webroot.contains(":") && !webroot.startsWith("/")) {
myroot = new File(System.getProperty(Application.RESNAME_APP_HOME), webroot);
}
resourceFactory.register(Server.RESNAME_SERVER_ROOT, String.class, myroot.getCanonicalPath());
resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile());
resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath());
//加入指定的classpath
Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", ""));
this.serverThread.setContextClassLoader(this.serverClassLoader);
}
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
server.init(this.serverConf);
//init之后才有Executor
//废弃 @since 2.3.0
// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, Executor.class, server.getWorkExecutor());
// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ExecutorService.class, server.getWorkExecutor());
// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ThreadPoolExecutor.class, server.getWorkExecutor());
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
String interceptorClass = this.serverConf.getValue("interceptor", "");
if (!interceptorClass.isEmpty()) {
Class clazz = serverClassLoader.loadClass(interceptorClass);
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
this.interceptor = (NodeInterceptor) clazz.getDeclaredConstructor().newInstance();
}
ClassFilter<Service> serviceFilter = createServiceClassFilter();
if (application.isSingletonMode()) { //singleton模式下只加载指定的Service
final String ssc = System.getProperty("red" + "kale.singleton.serviceclass");
final String extssc = System.getProperty("red" + "kale.singleton.extserviceclasses");
if (ssc != null) {
final List<String> sscList = new ArrayList<>();
sscList.add(ssc);
if (extssc != null && !extssc.isEmpty()) {
for (String s : extssc.split(",")) {
if (!s.isEmpty()) sscList.add(s);
}
}
serviceFilter.setExpectPredicate(c -> !sscList.contains(c));
}
}
ClassFilter<Filter> filterFilter = createFilterClassFilter();
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter otherFilter = createOtherClassFilter();
long s = System.currentTimeMillis();
ClassFilter.Loader.load(application.getHome(), serverClassLoader, ((application.excludelibs != null ? (application.excludelibs + ";") : "") + serverConf.getValue("excludelibs", "")).split(";"), serviceFilter, filterFilter, servletFilter, otherFilter);
long e = System.currentTimeMillis() - s;
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
loadService(serviceFilter, otherFilter); //必须在servlet之前
if (!application.isSingletonMode()) { //非singleton模式下才加载Filter、Servlet
loadFilter(filterFilter, otherFilter);
loadServlet(servletFilter, otherFilter);
postLoadServlets();
}
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
}
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() {
final NodeServer self = this;
//---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory();
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
final AnyValue resources = application.config.getAnyValue("resources");
final String confURI = appResFactory.find(RESNAME_APP_CONF, String.class);
final Map<String, SimpleEntry<Class, AnyValue>> cacheResource = new HashMap<>();
final Map<String, SimpleEntry<Class, AnyValue>> dataResources = new HashMap<>();
if (resources != null) {
for (AnyValue sourceConf : resources.getAnyValues("source")) {
try {
String classval = sourceConf.getValue("value");
Class type = null;
if (classval == null || classval.isEmpty()) {
RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class);
List<CacheSourceProvider> providers = new ArrayList<>();
Iterator<CacheSourceProvider> it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator();
while (it.hasNext()) {
CacheSourceProvider s = it.next();
if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName());
if (s != null && s.acceptsConf(sourceConf)) {
providers.add(s);
}
}
Collections.sort(providers, (a, b) -> {
Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class);
Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
});
for (CacheSourceProvider provider : providers) {
type = provider.sourceClass();
if (type != null) break;
}
} else {
type = serverClassLoader.loadClass(classval);
}
if (type == DataSource.class) {
type = DataMemorySource.class;
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
if (itemConf.getValue("name", "").contains(DataSources.JDBC_URL)) {
type = DataJdbcSource.class;
break;
}
}
}
if (!Service.class.isAssignableFrom(type)) {
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
} else if (CacheSource.class.isAssignableFrom(type)) {
cacheResource.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
} else if (DataSource.class.isAssignableFrom(type)) {
dataResources.put(sourceConf.getValue("name", ""), new SimpleEntry(type, 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);
//------------------------------------- 注册 Local AutoLoad(false) Service --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
Class<Service> resServiceType = Service.class;
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 AutoLoad Service
if (!Service.class.isAssignableFrom(field.getType())) return;
resServiceType = (Class) field.getType();
if (resServiceType.getAnnotation(Local.class) == null) return;
AutoLoad al = resServiceType.getAnnotation(AutoLoad.class);
if (al == null || al.value()) return;
//ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory);
SncpClient client = src instanceof Service ? Sncp.getSncpClient((Service) src) : null;
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final Set<String> groups = new HashSet<>();
Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, null, appResFactory, appSncpTranFactory, sncpAddr, groups, null);
appResFactory.register(resourceName, resServiceType, service);
field.set(src, service);
rf.inject(service, self); // 给其可能包含@Resource的字段赋值;
if (!application.isCompileMode()) service.init(null);
logger.info("[" + Thread.currentThread().getName() + "] Load Service(@Local @AutoLoad service = " + resServiceType.getSimpleName() + ", resourceName = '" + resourceName + "')");
} catch (Exception e) {
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + src + " error", e);
}
}, Service.class);
//------------------------------------- 注册 DataSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
SimpleEntry<Class, AnyValue> resEntry = dataResources.get(resourceName);
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
DataSource source = null;
if (sourceConf != null) {
final Class sourceType = resEntry.getKey();
if (sourceType == DataJdbcSource.class) {
source = DataSources.createDataSource(resourceName, sourceConf);
} else {
boolean can = false;
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
for (Constructor cr : sourceType.getConstructors()) {
if (cr.getParameterCount() == 0) {
can = true;
break;
}
}
if (DataSource.class.isAssignableFrom(sourceType) && can) { // 必须有空构造函数
if (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) {
source = (DataSource) sourceType.getConstructor().newInstance();
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
} else {
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient(srcService);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final Set<String> groups = new HashSet<>();
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
}
}
}
}
if (source == null) {
source = DataSources.createDataSource(confURI, resourceName); //从persistence.xml配置中创建
}
RedkaleClassLoader.putReflectionPublicConstructors(source.getClass(), source.getClass().getName());
application.dataSources.add(source);
ResourceType rt = source.getClass().getAnnotation(ResourceType.class);
if (rt != null && rt.value() != DataSource.class) {
appResFactory.register(resourceName, rt.value(), source);
} else if (source instanceof SearchSource) {
appResFactory.register(resourceName, SearchSource.class, source);
}
appResFactory.register(resourceName, DataSource.class, source);
field.set(src, source);
rf.inject(source, self); // 给AsyncGroup和其他@Resource的字段赋值;
//NodeServer.this.watchFactory.inject(src);
if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf);
logger.info("[" + Thread.currentThread().getName() + "] Load DataSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')");
} catch (Exception e) {
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject to " + src + " error", e);
}
}, DataSource.class);
//------------------------------------- 注册 CacheSource --------------------------------------------------------
resourceFactory.register(new ResourceFactory.ResourceLoader() {
@Override
public void load(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)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + src);
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient(srcService);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName);
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
if (sourceConf == null) {
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
}
Class sourceType0 = CacheMemorySource.class;
if (sourceConf != null) {
String classval = sourceConf.getValue("value");
if (classval == null || classval.isEmpty()) {
RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class);
List<CacheSourceProvider> providers = new ArrayList<>();
Iterator<CacheSourceProvider> it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator();
while (it.hasNext()) {
CacheSourceProvider s = it.next();
if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName());
if (s != null && s.acceptsConf(sourceConf)) {
providers.add(s);
}
}
Collections.sort(providers, (a, b) -> {
Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class);
Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
});
for (CacheSourceProvider provider : providers) {
sourceType0 = provider.sourceClass();
if (sourceType0 != null) break;
}
} else {
sourceType0 = serverClassLoader.loadClass(classval);
}
}
final Class sourceType = sourceType0;
Object source = null;
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
source = sourceType == CacheMemorySource.class ? new CacheMemorySource(resourceName)
: (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) ? sourceType.getConstructor().newInstance()
: (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, null, Sncp.getConf(srcService));
Type genericType = field.getGenericType();
application.cacheSources.add((CacheSource) source);
appResFactory.register(resourceName, CacheSource.class, source);
if (genericType != CacheSource.class) {
appResFactory.register(resourceName, genericType, source);
}
}
field.set(src, source);
rf.inject(source, self); //
if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf);
if ((src instanceof org.redkale.net.http.WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
if (source != null && source.getClass().getAnnotation(Local.class) == null) { //本地模式的Service不生成SncpServlet
sncpServer.getSncpServer().addSncpServlet((Service) source);
}
//logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
}
logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')");
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
}
@Override
public boolean autoNone() {
return false;
}
}, CacheSource.class);
//------------------------------------- 注册 WebSocketNode --------------------------------------------------------
resourceFactory.register(new ResourceFactory.ResourceLoader() {
@Override
public void load(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; //远程模式不需要注入 WebSocketNode
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (nodeService == null) {
final HashSet<String> groups = new HashSet<>();
if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup);
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, Sncp.getMessageAgent((Service) src), application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null);
(isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService);
((org.redkale.net.http.WebSocketNodeService) nodeService).setName(resourceName);
}
resourceFactory.inject(nodeService, self);
MessageAgent messageAgent = Sncp.getMessageAgent((Service) src);
if (messageAgent != null && Sncp.getMessageAgent(nodeService) == null) Sncp.setMessageAgent(nodeService, messageAgent);
field.set(src, nodeService);
if (Sncp.isRemote(nodeService)) {
remoteServices.add(nodeService);
} else {
rf.inject(nodeService); //动态加载的Service也存在按需加载的注入资源
localServices.add(nodeService);
interceptorServices.add(nodeService);
if (consumer != null) consumer.accept(null, nodeService);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
}
}
@Override
public boolean autoNone() {
return false;
}
}, WebSocketNode.class);
}
@SuppressWarnings("unchecked")
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
if (serviceFilter == null) return;
final long starts = System.currentTimeMillis();
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
final ResourceFactory appResourceFactory = application.getResourceFactory();
final TransportFactory appSncpTransFactory = application.getSncpTransportFactory();
for (FilterEntry<? extends Service> entry : entrys) { //service实现类
final Class<? extends Service> serviceImplClass = entry.getType();
if (Modifier.isFinal(serviceImplClass.getModifiers())) continue; //修饰final的类跳过
if (!Modifier.isPublic(serviceImplClass.getModifiers())) continue;
if (serviceImplClass.getAnnotation(SncpDyn.class) != null) continue; //动态生成的跳过
if (entry.isExpect()) {
if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
}
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
if (!Sncp.isRemote(oldother)) interceptorServices.add(oldother);
continue;
}
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup);
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !serviceImplClass.isInterface() && !Modifier.isAbstract(serviceImplClass.getModifiers())) //非SNCP的Server通常是单点服务
|| groups.contains(this.sncpGroup) //本地IP含在内的
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|| serviceImplClass.getAnnotation(Local.class) != null;//本地模式
if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try {
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的 通常为BaseService
if (!serviceImplClass.getName().startsWith("org.redkale.") && !serviceImplClass.getSimpleName().contains("Base")) {
logger.log(Level.FINE, serviceImplClass + " cannot load because not found less one public non-final method");
}
return;
}
RedkaleClassLoader.putReflectionPublicMethods(serviceImplClass.getName());
MessageAgent agent = null;
if (entry.getProperty() != null && entry.getProperty().getValue("mq") != null) {
agent = application.getMessageAgent(entry.getProperty().getValue("mq"));
if (agent != null) messageAgents.put(agent.getName(), agent);
}
Service service;
final boolean ws = src instanceof WebSocketServlet;
if (ws || localed) { //本地模式
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, agent, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
} else {
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, agent, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
}
if (service instanceof org.redkale.net.http.WebSocketNodeService) {
((org.redkale.net.http.WebSocketNodeService) service).setName(resourceName);
if (agent != null) Sncp.setMessageAgent(service, agent);
}
final Class restype = Sncp.getResourceType(service);
if (rf.find(resourceName, restype) == null) {
regFactory.register(resourceName, restype, service);
} else if (isSNCP() && !entry.isAutoload()) {
throw new RuntimeException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + resourceName + ", group:" + groups + ") is repeat.");
}
if (Sncp.isRemote(service)) {
remoteServices.add(service);
if (agent != null) sncpRemoteAgents.put(agent.getName(), agent);
} else {
if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
localServices.add(service);
interceptorServices.add(service);
if (consumer != null) consumer.accept(agent, service);
}
} catch (RuntimeException ex) {
throw ex;
} catch (Exception e) {
throw new RuntimeException(e);
}
};
if (entry.isExpect()) {
ResourceType rty = entry.getType().getAnnotation(ResourceType.class);
resourceFactory.register(resourceLoader, rty == null ? entry.getType() : rty.value());
} else {
resourceLoader.load(resourceFactory, null, entry.getName(), null, false);
}
}
application.servicecdl.countDown();
application.servicecdl.await();
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
//---------------- inject ----------------
new ArrayList<>(localServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this);
});
new ArrayList<>(remoteServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this);
calcMaxLength(y);
});
if (sb != null) {
remoteServices.forEach(y -> {
sb.append(localThreadName).append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)).append(" load and inject").append(LINE_SEPARATOR);
});
}
if (isSNCP() && !sncpRemoteAgents.isEmpty()) {
sncpRemoteAgents.values().forEach(agent -> {
// agent.putSncpResp((NodeSncpServer) this);
// agent.startSncpRespConsumer();
});
}
//----------------- init -----------------
List<Service> swlist = new ArrayList<>(localServices);
swlist.forEach(y -> calcMaxLength(y));
swlist.sort((o1, o2) -> {
Priority p1 = o1.getClass().getAnnotation(Priority.class);
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();
long preinits = System.currentTimeMillis();
preInitServices(localServices, remoteServices);
long preinite = System.currentTimeMillis() - preinits;
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
if (application.isCompileMode()) {
localServices.stream().forEach(y -> {
String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength);
if (slist != null) slist.add(new StringBuilder().append(localThreadName).append(serstr).append(" load").append(LINE_SEPARATOR).toString());
});
} else {
localServices.stream().forEach(y -> {
long s = System.currentTimeMillis();
y.init(Sncp.getConf(y));
long e = System.currentTimeMillis() - s;
String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength);
if (slist != null) slist.add(new StringBuilder().append(localThreadName).append(serstr).append(" load and init in ").append(e < 10 ? " " : (e < 100 ? " " : "")).append(e).append(" ms").append(LINE_SEPARATOR).toString());
});
}
if (slist != null && sb != null) {
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
for (String s : wlist) {
sb.append(s);
}
sb.append(localThreadName).append("All Services load cost ").append(System.currentTimeMillis() - starts).append(" ms" + LINE_SEPARATOR);
}
if (sb != null && preinite > 10) sb.append(localThreadName).append(ClusterAgent.class.getSimpleName()).append(" register ").append(preinite).append(" ms" + LINE_SEPARATOR);
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
private void calcMaxLength(Service y) { //计算toString中的长度
maxNameLength = Math.max(maxNameLength, Sncp.getResourceName(y).length());
maxTypeLength = Math.max(maxTypeLength, Sncp.getResourceType(y).getName().length() + 1);
}
//Service.init执行之前调用
protected void preInitServices(Set<Service> localServices, Set<Service> remoteServices) {
final ClusterAgent cluster = application.clusterAgent;
if (!application.isCompileMode() && cluster != null) {
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
String protocol = pros.value().toUpperCase();
if (!cluster.containsProtocol(protocol)) return;
if (!cluster.containsPort(server.getSocketAddress().getPort())) return;
cluster.register(this, protocol, localServices, remoteServices);
}
}
//loadServlet执行之后调用
protected void postLoadServlets() {
}
//Service.destroy执行之前调用
protected void preDestroyServices(Set<Service> localServices, Set<Service> remoteServices) {
if (!application.isCompileMode() && application.clusterAgent != null) { //服务注销
final ClusterAgent cluster = application.clusterAgent;
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
String protocol = pros.value().toUpperCase();
if (cluster.containsProtocol(protocol) && cluster.containsPort(server.getSocketAddress().getPort())) {
cluster.deregister(this, protocol, localServices, remoteServices);
afterClusterDeregisterOnPreDestroyServices(cluster, protocol);
}
}
if (!application.isCompileMode() && !this.messageAgents.isEmpty()) { //MQ
}
}
protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) {
}
//Server.start执行之后调用
protected void postStartServer(Set<Service> localServices, Set<Service> remoteServices) {
}
protected abstract ClassFilter<Filter> createFilterClassFilter();
protected abstract ClassFilter<Servlet> createServletClassFilter();
protected ClassFilter createOtherClassFilter() {
return null;
}
protected ClassFilter<Service> createServiceClassFilter() {
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,
Class inter, Class[] excludeSuperClasses, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, null);
if (properties == null && properties == null) {
cf.setRefused(true);
return cf;
}
if (this.serverConf == null) {
cf.setRefused(true);
return cf;
}
AnyValue[] proplist = this.serverConf.getAnyValues(properties);
if (proplist == null || proplist.length < 1) {
cf.setRefused(true);
return cf;
}
cf = null;
for (AnyValue list : proplist) {
AnyValue.DefaultAnyValue prop = null;
String sc = list.getValue("groups");
String mq = list.getValue("mq");
if (sc != null) {
sc = sc.trim();
if (sc.endsWith(";")) sc = sc.substring(0, sc.length() - 1);
}
if (sc == null) sc = localGroup;
if (sc != null || mq != null) {
prop = new AnyValue.DefaultAnyValue();
if (sc != null) prop.addValue("groups", sc);
if (mq != null) prop.addValue("mq", mq);
}
ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop);
for (AnyValue av : list.getAnyValues(property)) { // <service>、<filter>、<servlet> 节点
final AnyValue[] items = av.getAnyValues("property");
if (av instanceof AnyValue.DefaultAnyValue && items.length > 0) { //存在 <property>节点
AnyValue.DefaultAnyValue dav = AnyValue.DefaultAnyValue.create();
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
if (strings != null) { //将<service>、<filter>、<servlet>节点的属性值传给dav
for (AnyValue.Entry<String> en : strings) {
dav.addValue(en.name, en.getValue());
}
}
final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys();
if (anys != null) {
for (AnyValue.Entry<AnyValue> en : anys) { //将<service>、<filter>、<servlet>节点的非property属性节点传给dav
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
}
}
AnyValue.DefaultAnyValue ps = AnyValue.DefaultAnyValue.create();
for (AnyValue item : items) {
ps.addValue(item.getValue("name"), item.getValue("value"));
}
dav.addValue("properties", ps);
av = dav;
}
if (!av.getBoolValue("ignore", false)) {
filter.filter(av, av.getValue("value"), false);
}
}
if (list.getBoolValue("autoload", true)) {
String includes = list.getValue("includes", "");
String excludes = list.getValue("excludes", "");
filter.setIncludePatterns(includes.split(";"));
filter.setExcludePatterns(excludes.split(";"));
} else if (ref2 == null || ref2 == Annotation.class) { //service如果是autoload=false则不需要加载
filter.setRefused(true);
} else if (ref2 != Annotation.class) {
filter.setAnnotationClass(ref2);
}
cf = (cf == null) ? filter : cf.or(filter);
}
return cf;
}
public abstract InetSocketAddress getSocketAddress();
public boolean isSNCP() {
return false;
}
public boolean isWATCH() {
return false;
}
public Application getApplication() {
return application;
}
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() {
return sncpAddress;
}
public AnyValue getServerConf() {
return serverConf;
}
public Logger getLogger() {
return logger;
}
public String getSncpGroup() {
return sncpGroup;
}
public void start() throws IOException {
if (interceptor != null) interceptor.preStart(this);
server.start();
postStartServer(localServices, remoteServices);
}
public void shutdown() throws IOException {
if (interceptor != null) interceptor.preShutdown(this);
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final boolean finest = logger.isLoggable(Level.FINEST);
preDestroyServices(localServices, remoteServices);
localServices.forEach(y -> {
long s = System.currentTimeMillis();
if (finest) logger.finest(y + " is destroying");
y.destroy(Sncp.getConf(y));
if (finest) logger.finest(y + " was destroyed");
long e = System.currentTimeMillis() - s;
if (e > 2 && sb != null) {
sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
}
});
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
server.shutdown();
}
public void command(String cmd) throws IOException {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final boolean finest = logger.isLoggable(Level.FINEST);
localServices.forEach(y -> {
Set<Method> methods = new HashSet<>();
Class loop = y.getClass();
//do { public方法不用递归
for (Method m : loop.getMethods()) {
Command c = m.getAnnotation(Command.class);
if (c == null) continue;
if (Modifier.isStatic(m.getModifiers())) continue;
if (m.getReturnType() != void.class) continue;
if (m.getParameterCount() != 1) continue;
if (m.getParameterTypes()[0] != String.class) continue;
methods.add(m);
}
//} while ((loop = loop.getSuperclass()) != Object.class);
if (methods.isEmpty()) return;
long s = System.currentTimeMillis();
Method one = null;
try {
for (Method method : methods) {
one = method;
method.invoke(y, cmd);
}
} catch (Exception ex) {
logger.log(Level.SEVERE, one + " run error, cmd = " + cmd, ex);
}
long e = System.currentTimeMillis() - s;
if (e > 10 && sb != null) {
sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)).append(" command (").append(cmd).append(") ").append(e).append("ms").append(LINE_SEPARATOR);
}
});
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
public <T extends Server> T getServer() {
return (T) server;
}
public Set<Service> getInterceptorServices() {
return new LinkedHashSet<>(interceptorServices);
}
public Set<Service> getLocalServices() {
return new LinkedHashSet<>(localServices);
}
public Set<Service> getRemoteServices() {
return new LinkedHashSet<>(remoteServices);
}
public String getThreadName() {
return this.threadName;
}
}

View File

@@ -10,9 +10,10 @@ import java.net.*;
import java.util.*;
import java.util.logging.Level;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.mq.MessageAgent;
import org.redkale.net.*;
import org.redkale.net.sncp.*;
import org.redkale.service.Service;
import org.redkale.service.*;
import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
@@ -24,7 +25,7 @@ import org.redkale.util.AnyValue.DefaultAnyValue;
*
* @author zhangjx
*/
@NodeProtocol({"SNCP"})
@NodeProtocol("SNCP")
public class NodeSncpServer extends NodeServer {
protected final SncpServer sncpServer;
@@ -32,19 +33,20 @@ public class NodeSncpServer extends NodeServer {
private NodeSncpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server;
this.consumer = sncpServer == null ? null : x -> sncpServer.addSncpServlet(x);
this.consumer = sncpServer == null || application.isSingletonMode() ? null : (agent, x) -> {//singleton模式下不生成SncpServlet
if (x.getClass().getAnnotation(Local.class) != null) return; //本地模式的Service不生成SncpServlet
SncpDynServlet servlet = sncpServer.addSncpServlet(x);
dynServletMap.put(x, servlet);
if (agent != null) agent.putService(this, x, servlet);
};
}
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
if (serconf != null && serconf.getAnyValue("rest") != null) {
((AnyValue.DefaultAnyValue) serconf).addValue("_$sncp", "true");
return new NodeHttpServer(application, serconf);
}
return new NodeSncpServer(application, serconf);
}
private static Server createServer(Application application, AnyValue serconf) {
return new SncpServer(application.getStartTime(), application.getResourceFactory().createChild());
return new SncpServer(application, application.getStartTime(), serconf, application.getResourceFactory().createChild());
}
@Override
@@ -52,8 +54,8 @@ public class NodeSncpServer extends NodeServer {
return sncpServer == null ? null : sncpServer.getSocketAddress();
}
public void consumerAccept(Service service) {
if (this.consumer != null) this.consumer.accept(service);
public void consumerAccept(MessageAgent messageAgent, Service service) {
if (this.consumer != null) this.consumer.accept(messageAgent, service);
}
@Override
@@ -62,11 +64,11 @@ public class NodeSncpServer extends NodeServer {
//-------------------------------------------------------------------
if (sncpServer == null) return; //调试时server才可能为null
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
List<SncpServlet> servlets = sncpServer.getSncpServlets();
Collections.sort(servlets);
for (SncpServlet en : servlets) {
if (sb != null) sb.append(threadName).append(" Load ").append(en).append(LINE_SEPARATOR);
if (sb != null) sb.append(localThreadName).append(" Load ").append(en).append(LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
}
@@ -88,22 +90,25 @@ public class NodeSncpServer extends NodeServer {
@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() + "] ";
final String localThreadName = "[" + 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();
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
final SncpFilter filter = clazz.getDeclaredConstructor().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.append(localThreadName).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 {
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName());
}
@Override

View File

@@ -16,7 +16,7 @@ import org.redkale.watch.*;
*
* @author zhangjx
*/
@NodeProtocol({"WATCH"})
@NodeProtocol("WATCH")
public class NodeWatchServer extends NodeHttpServer {
public NodeWatchServer(Application application, AnyValue serconf) {
@@ -24,16 +24,19 @@ public class NodeWatchServer extends NodeHttpServer {
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
}

View File

@@ -0,0 +1,86 @@
/*
* 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.reflect.Modifier;
import javax.persistence.Entity;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.Decodeable;
import org.redkale.convert.bson.BsonFactory;
import org.redkale.convert.json.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* 执行一次Application.run提前获取所有动态类
*
* @author zhangjx
* @since 2.5.0
*/
public class PrepareCompiler {
// public static void main(String[] args) throws Exception {
// new PrepareCompiler().run();
// }
public Application run() throws Exception {
final Application application = new Application(false, true, Application.loadAppConfig());
application.init();
for (ApplicationListener listener : application.listeners) {
listener.preStart(application);
}
for (ApplicationListener listener : application.listeners) {
listener.preCompile(application);
}
application.start();
final boolean hasSncp = application.getNodeServers().stream().filter(v -> v instanceof NodeSncpServer).findFirst().isPresent();
final String[] exlibs = (application.excludelibs != null ? (application.excludelibs + ";") : "").split(";");
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class, (Class[]) null);
final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class, (Class[]) null);
final ClassFilter<?> filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class, (Class[]) null);
ClassFilter.Loader.load(application.getHome(), application.getClassLoader(), exlibs, entityFilter, beanFilter, filterFilter);
for (FilterEntry en : entityFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
try {
application.dataSources.forEach(source -> source.compile(clz));
JsonFactory.root().loadEncoder(clz);
if (hasSncp) BsonFactory.root().loadEncoder(clz);
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) BsonFactory.root().loadDecoder(clz);
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : beanFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
try {
JsonFactory.root().loadEncoder(clz);
if (hasSncp) BsonFactory.root().loadEncoder(clz);
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) BsonFactory.root().loadDecoder(clz);
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : filterFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
try {
FilterNodeBean.load(clz);
} catch (Exception e) {
}
}
for (ApplicationListener listener : application.listeners) {
listener.postCompile(application);
}
application.shutdown();
return application;
}
}

View File

@@ -41,7 +41,7 @@
html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>');
html.push('<td class="s">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
html.push('<td class="s" style="width:80px;">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
var paramshtml = [];
paramshtml.push('<table class="subtable">');
for (var p = 0; p < action.params.length; p++) {
@@ -55,8 +55,8 @@
} else {
var w = param.required ? "font-weight:bold;" : "";
var c = ' style="' + w + '"';
if (param.src == "HEADER") c = ' style="color:red;' + w + '"';
if (param.src == "COOKIE") c = ' style="color:blue;' + w + '"';
if (param.style == "HEADER") c = ' style="color:red;' + w + '"';
if (param.style == "COOKIE") c = ' style="color:blue;' + w + '"';
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
}
}

View File

@@ -6,6 +6,7 @@
package org.redkale.boot.watch;
import org.redkale.service.AbstractService;
import org.redkale.util.Comment;
import org.redkale.watch.WatchService;
/**
@@ -14,4 +15,15 @@ import org.redkale.watch.WatchService;
*/
public abstract class AbstractWatchService extends AbstractService implements WatchService {
/**
* 缺少参数
*/
@Comment("缺少参数")
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
/**
* 执行异常
*/
@Comment("执行异常")
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
}

View File

@@ -33,9 +33,9 @@ public class FilterWatchService extends AbstractWatchService {
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
@Resource
private Application application;
protected Application application;
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
@RestParam(name = "server", comment = "Server节点名") final String serverName,
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
@@ -47,4 +47,34 @@ public class FilterWatchService extends AbstractWatchService {
}
return RetResult.success();
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
@RestMapping(name = "test5", auth = false, comment = "预留")
public RetResult test5() {
return RetResult.success();
}
@RestMapping(name = "test6", auth = false, comment = "预留")
public RetResult test6() {
return RetResult.success();
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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.InetSocketAddress;
import java.util.*;
import java.util.stream.Stream;
import javax.annotation.Resource;
import org.redkale.boot.*;
import org.redkale.net.Server;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.Comment;
/**
*
* @author zhangjx
*/
@RestService(name = "server", catalog = "watch", repair = false)
public class ServerWatchService extends AbstractWatchService {
@Comment("不存在的Server节点")
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
@Comment("更改Server监听地址端口失败")
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
@Resource
protected Application application;
@RestMapping(name = "info", comment = "单个Server信息查询")
public RetResult info(@RestParam(name = "#port:") final int port) {
Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
return new RetResult(formatToMap(node));
}
@RestMapping(name = "infos", comment = "Server信息查询")
public RetResult infos() {
Map<String, Object> rs = new LinkedHashMap<>();
for (NodeServer ns : application.getNodeServers()) {
Server server = ns.getServer();
rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns));
}
return new RetResult(rs);
}
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
final Server server = node.getServer();
InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
try {
server.changeAddress(application, newAddr);
} catch (IOException e) {
e.printStackTrace();
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error");
}
return RetResult.success();
}
private Map<String, Object> formatToMap(NodeServer node) {
Server server = node.getServer();
Map<String, Object> rs = new LinkedHashMap<>();
String protocol = server.getNetprotocol();
if (node instanceof NodeSncpServer) {
protocol += "/SNCP";
} else if (node instanceof NodeWatchServer) {
protocol += "/WATCH";
} else if (node instanceof NodeHttpServer) {
protocol += "/HTTP";
} else {
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
protocol += "/" + np.value();
}
rs.put("name", server.getName());
rs.put("protocol", protocol);
rs.put("address", server.getSocketAddress());
rs.put("backlog", server.getBacklog());
rs.put("bufferCapacity", server.getBufferCapacity());
rs.put("bufferPoolSize", server.getBufferPoolSize());
rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name());
rs.put("maxbody", server.getMaxbody());
rs.put("maxconns", server.getMaxconns());
rs.put("serverStartTime", server.getServerStartTime());
rs.put("responsePoolSize", server.getResponsePoolSize());
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());
rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds());
rs.put("createConnectionCount", server.getCreateConnectionCount());
rs.put("livingConnectionCount", server.getLivingConnectionCount());
rs.put("closedConnectionCount", server.getClosedConnectionCount());
return rs;
}
}

View File

@@ -0,0 +1,199 @@
/*
* 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.lang.reflect.*;
import java.util.*;
import javax.annotation.Resource;
import org.redkale.boot.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.*;
/**
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@RestService(name = "service", catalog = "watch", repair = false)
public class ServiceWatchService extends AbstractWatchService {
@Comment("没有找到目标Service")
public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001;
@Resource
protected Application application;
@RestConvert(type = void.class)
@RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容")
public RetResult setField(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field,
@RestParam(name = "value", comment = "字段值") String value) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
try {
Field fieldObj = null;
do {
try {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
fieldObj.setAccessible(true);
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
return RetResult.success();
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
@RestConvert(type = void.class)
@RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容")
public RetResult getField(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
try {
Field fieldObj = null;
do {
try {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
fieldObj.setAccessible(true);
return new RetResult(fieldObj.get(dest));
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
@RestConvert(type = void.class)
@RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法")
public RetResult runMethod(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "method", comment = "Service的方法名") String method,
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
if (name == null) name = "";
if (type == null) type = "";
if (method == null) method = "";
type = type.trim();
method = method.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (method.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
final int paramcount = params == null ? 0 : params.size();
if (paramtypes != null && paramcount != paramtypes.size()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
try {
Method methodObj = null;
do {
try {
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equals(method) && m.getParameterCount() == paramcount) {
boolean flag = true;
if (paramtypes != null) {
Class[] pts = m.getParameterTypes();
for (int i = 0; i < pts.length; i++) {
if (!pts[i].getName().endsWith(paramtypes.get(i))) {
flag = false;
break;
}
}
}
if (flag) {
methodObj = m;
break;
}
}
}
if (methodObj != null) break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (methodObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")");
methodObj.setAccessible(true);
if (paramcount < 1) return new RetResult(methodObj.invoke(dest));
Object[] paramObjs = new Object[paramcount];
Type[] pts = methodObj.getGenericParameterTypes();
for (int i = 0; i < paramObjs.length; i++) {
paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i));
}
return new RetResult(methodObj.invoke(dest, paramObjs));
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
protected Object findService(String name, String type) {
Object dest = null;
for (NodeServer ns : application.getNodeServers()) {
ResourceFactory resFactory = ns.getResourceFactory();
List list = resFactory.query((n, s) -> name.equals(n) && s != null && s.getClass().getName().endsWith(type));
if (list == null || list.isEmpty()) continue;
dest = list.get(0);
}
if (dest == null) return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
return dest;
}
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
//待开发
return RetResult.success();
}
@RestMapping(name = "reloadService", auth = false, comment = "重新加载Service")
public RetResult reloadService(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "stopService", auth = false, comment = "动态停止Service")
public RetResult stopService(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "findService", auth = false, comment = "查找Service")
public RetResult find(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) {
//待开发
return RetResult.success();
}
}

View File

@@ -20,18 +20,18 @@ import org.redkale.net.http.*;
public class ServletWatchService extends AbstractWatchService {
@Resource
private Application application;
protected Application application;
@Resource
private TransportFactory transportFactory;
protected TransportFactory transportFactory;
//
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
// @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet")
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
// //待开发
// return RetResult.success();
// }
//
// @RestMapping(name = "stop", auth = false, comment = "动态停止Servlet")
// @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet")
// public RetResult stopServlet(String type) {
// //待开发
// return RetResult.success();

View File

@@ -36,10 +36,10 @@ public class TransportWatchService extends AbstractWatchService {
public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003;
@Resource
private Application application;
protected Application application;
@Resource
private TransportFactory transportFactory;
protected TransportFactory transportFactory;
@RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点")
public List<TransportGroupInfo> listNodes() {
@@ -72,15 +72,6 @@ public class TransportWatchService extends AbstractWatchService {
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);
@@ -90,7 +81,7 @@ public class TransportWatchService extends AbstractWatchService {
break;
}
}
application.restoreConfig();
//application.restoreConfig();
}
return RetResult.success();
}
@@ -114,15 +105,6 @@ public class TransportWatchService extends AbstractWatchService {
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")) {
@@ -131,8 +113,28 @@ public class TransportWatchService extends AbstractWatchService {
break;
}
}
application.restoreConfig();
//application.restoreConfig();
}
return RetResult.success();
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
}

View File

@@ -0,0 +1,327 @@
/*
* 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.cluster;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import javax.annotation.Resource;
import org.redkale.boot.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.service.Service;
import org.redkale.source.CacheSource;
import org.redkale.util.*;
/**
* 使用CacheSource实现的第三方服务发现管理接口cluster
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.3.0
*/
public class CacheClusterAgent extends ClusterAgent implements Resourcable {
@Resource(name = "$")
private CacheSource source;
private String sourceName;
protected int ttls = 10; //定时检查的秒数
protected ScheduledThreadPoolExecutor scheduler;
//可能被HttpMessageClient用到的服务 key: servicename
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
//可能被mqtp用到的服务 key: servicename
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> mqtpAddressMap = new ConcurrentHashMap<>();
@Override
public void init(AnyValue config) {
super.init(config);
this.sourceName = getSourceName();
AnyValue[] properties = config.getAnyValues("property");
for (AnyValue property : properties) {
if ("ttls".equalsIgnoreCase(property.getValue("name"))) {
this.ttls = Integer.parseInt(property.getValue("value", "").trim());
if (this.ttls < 5) this.ttls = 10;
}
}
}
@Override
public void destroy(AnyValue config) {
if (scheduler != null) scheduler.shutdownNow();
}
public String getSourceName() {
AnyValue[] properties = config.getAnyValues("property");
for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) {
this.sourceName = property.getValue("value");
return this.sourceName;
}
}
return null;
}
@Override
public String resourceName() {
return sourceName;
}
@Override //ServiceLoader时判断配置是否符合当前实现类
public boolean acceptsConf(AnyValue config) {
if (config == null) return false;
AnyValue[] properties = config.getAnyValues("property");
if (properties == null || properties.length == 0) return false;
for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) return true;
}
return false;
}
@Override
public void start() {
if (this.scheduler == null) {
this.scheduler = new ScheduledThreadPoolExecutor(4, (Runnable r) -> {
final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Task-Thread");
t.setDaemon(true);
return t;
});
this.scheduler.scheduleAtFixedRate(() -> {
try {
checkApplicationHealth();
checkHttpAddressHealth();
loadMqtpAddressHealth();
localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> {
checkLocalHealth(entry);
});
remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> {
updateSncpTransport(entry);
});
} catch (Exception e) {
logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e instanceof CompletionException ? ((CompletionException) e).getCause() : e);
}
}, Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS);
}
}
protected void loadMqtpAddressHealth() {
List<String> keys = source.queryKeysStartsWith("cluster.mqtp:");
keys.forEach(servicename -> {
try {
this.mqtpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS));
} catch (Exception e) {
logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + servicename + " error", e);
}
});
}
protected void checkHttpAddressHealth() {
try {
this.httpAddressMap.keySet().stream().forEach(servicename -> {
try {
this.httpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS));
} catch (Exception e) {
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + servicename + " error", e);
}
});
} catch (Exception ex) {
logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex);
}
}
protected void checkLocalHealth(final ClusterEntry entry) {
AddressEntry newaddr = new AddressEntry();
newaddr.addr = entry.address;
newaddr.nodeid = this.nodeid;
newaddr.time = System.currentTimeMillis();
source.hset(entry.checkname, entry.checkid, AddressEntry.class, newaddr);
}
@Override //获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段
public CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname) {
final Map<String, Collection<InetSocketAddress>> rsmap = new ConcurrentHashMap<>();
final String servicenamprefix = generateHttpServiceName(protocol, module, null) + ":";
mqtpAddressMap.keySet().stream().filter(k -> k.startsWith(servicenamprefix))
.forEach(sn -> rsmap.put(sn.substring(servicenamprefix.length()), mqtpAddressMap.get(sn)));
return CompletableFuture.completedFuture(rsmap);
}
@Override //获取HTTP远程服务的可用ip列表
public CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
final String servicename = generateHttpServiceName(protocol, module, resname);
Collection<InetSocketAddress> rs = httpAddressMap.get(servicename);
if (rs != null) return CompletableFuture.completedFuture(rs);
return queryAddress(servicename).thenApply(t -> {
httpAddressMap.put(servicename, t);
return t;
});
}
@Override
protected CompletableFuture<Collection<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
return queryAddress(entry.servicename);
}
private CompletableFuture<Collection<InetSocketAddress>> queryAddress(final String servicename) {
final CompletableFuture<Map<String, AddressEntry>> future = source.hmapAsync(servicename, AddressEntry.class, 0, 10000);
return future.thenApply(map -> {
final Set<InetSocketAddress> set = new HashSet<>();
map.forEach((n, v) -> {
if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) set.add(v.addr);
});
return set;
});
}
protected boolean isApplicationHealth() {
String servicename = generateApplicationServiceName();
String serviceid = generateApplicationServiceId();
AddressEntry entry = (AddressEntry) source.hget(servicename, serviceid, AddressEntry.class);
return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls;
}
protected void checkApplicationHealth() {
String checkname = generateApplicationServiceName();
String checkid = generateApplicationCheckId();
AddressEntry entry = new AddressEntry();
entry.addr = this.appAddress;
entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis();
source.hset(checkname, checkid, AddressEntry.class, entry);
}
@Override
public void register(Application application) {
if (isApplicationHealth()) throw new RuntimeException("application.nodeid=" + nodeid + " exists in cluster");
deregister(application);
String serviceid = generateApplicationServiceId();
String servicename = generateApplicationServiceName();
AddressEntry entry = new AddressEntry();
entry.addr = this.appAddress;
entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis();
source.hset(servicename, serviceid, AddressEntry.class, entry);
}
@Override
public void deregister(Application application) {
String servicename = generateApplicationServiceName();
source.remove(servicename);
}
@Override
protected ClusterEntry register(NodeServer ns, String protocol, Service service) {
deregister(ns, protocol, service, false);
//
ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service);
AddressEntry entry = new AddressEntry();
entry.addr = clusterEntry.address;
entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis();
source.hset(clusterEntry.servicename, clusterEntry.serviceid, AddressEntry.class, entry);
return clusterEntry;
}
@Override
protected void deregister(NodeServer ns, String protocol, Service service) {
deregister(ns, protocol, service, true);
}
protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) {
String servicename = generateServiceName(ns, protocol, service);
String serviceid = generateServiceId(ns, protocol, service);
ClusterEntry currEntry = null;
for (final ClusterEntry entry : localEntrys.values()) {
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) {
currEntry = entry;
break;
}
}
if (currEntry == null) {
for (final ClusterEntry entry : remoteEntrys.values()) {
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) {
currEntry = entry;
break;
}
}
}
source.hremove(servicename, serviceid);
if (realcanceled && currEntry != null) currEntry.canceled = true;
if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) {
deregister(ns, "mqtp", service, realcanceled);
}
}
@Override
protected String generateApplicationServiceName() {
return "cluster." + super.generateApplicationServiceName();
}
@Override
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
return "cluster." + super.generateServiceName(ns, protocol, service);
}
@Override
public String generateHttpServiceName(String protocol, String module, String resname) {
return "cluster." + super.generateHttpServiceName(protocol, module, resname);
}
@Override
protected String generateApplicationCheckName() {
return generateApplicationServiceName();
}
@Override
protected String generateApplicationCheckId() {
return generateApplicationServiceId();
}
@Override
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
return generateServiceName(ns, protocol, service);
}
@Override
protected String generateCheckId(NodeServer ns, String protocol, Service service) {
return generateServiceId(ns, protocol, service);
}
public static class AddressEntry {
public InetSocketAddress addr;
public int nodeid;
public long time;
public AddressEntry() {
}
public AddressEntry refresh() {
this.time = System.currentTimeMillis();
return this;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}
}

View File

@@ -0,0 +1,342 @@
/*
* 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.cluster;
import java.lang.ref.WeakReference;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Logger;
import javax.annotation.Resource;
import org.redkale.boot.*;
import static org.redkale.boot.Application.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.mq.MessageMultiConsumer;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.util.*;
/**
* 第三方服务发现管理接口cluster
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.1.0
*/
public abstract class ClusterAgent {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
@Resource(name = RESNAME_APP_NODEID)
protected int nodeid;
@Resource(name = RESNAME_APP_NAME)
protected String appName = "";
@Resource(name = RESNAME_APP_ADDR)
protected InetSocketAddress appAddress;
protected String name;
protected boolean waits;
protected String[] protocols; //必须全大写
protected int[] ports;
protected AnyValue config;
protected TransportFactory transportFactory;
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
public void init(AnyValue config) {
this.config = config;
this.name = config.getValue("name", "");
this.waits = config.getBoolValue("waits", false);
{
String ps = config.getValue("protocols", "").toUpperCase();
if (ps == null || ps.isEmpty()) ps = "SNCP;HTTP";
this.protocols = ps.split(";");
}
String ts = config.getValue("ports", "");
if (ts != null && !ts.isEmpty()) {
String[] its = ts.split(";");
List<Integer> list = new ArrayList<>();
for (String str : its) {
if (str.trim().isEmpty()) continue;
list.add(Integer.parseInt(str.trim()));
}
if (!list.isEmpty()) this.ports = list.stream().mapToInt(x -> x).toArray();
}
}
public void destroy(AnyValue config) {
}
//ServiceLoader时判断配置是否符合当前实现类
public abstract boolean acceptsConf(AnyValue config);
public boolean containsProtocol(String protocol) {
if (protocol == null || protocol.isEmpty()) return false;
return protocols == null || Utility.contains(protocols, protocol.toUpperCase());
}
public boolean containsPort(int port) {
if (ports == null || ports.length == 0) return true;
return Utility.contains(ports, port);
}
public abstract void register(Application application);
public abstract void deregister(Application application);
//注册服务, 在NodeService调用Service.init方法之前调用
public void register(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
if (localServices.isEmpty()) return;
//注册本地模式
for (Service service : localServices) {
if (!canRegister(protocol, service)) continue;
ClusterEntry htentry = register(ns, protocol, service);
localEntrys.put(htentry.serviceid, htentry);
if (protocol.toLowerCase().startsWith("http")) {
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
if (mmc != null) {
ClusterEntry mqentry = register(ns, "mqtp", service);
localEntrys.put(mqentry.serviceid, mqentry);
htentry.submqtp = true;
}
}
}
//远程模式加载IP列表, 只支持SNCP协议
if (ns.isSNCP()) {
for (Service service : remoteServices) {
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
updateSncpTransport(entry);
remoteEntrys.put(entry.serviceid, entry);
}
}
}
//注销服务, 在NodeService调用Service.destroy 方法之前调用
public void deregister(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
//注销本地模式 远程模式不注册
for (Service service : localServices) {
if (!canRegister(protocol, service)) continue;
deregister(ns, protocol, service);
}
afterDeregister(ns, protocol);
}
protected boolean canRegister(String protocol, Service service) {
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) return false;
AutoLoad al = service.getClass().getAnnotation(AutoLoad.class);
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return false;
if (service instanceof WebSocketNode) {
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) return false;
}
return true;
}
public void start() {
}
protected void afterDeregister(NodeServer ns, String protocol) {
if (!this.waits) return;
int s = intervalCheckSeconds();
if (s > 0) { //暂停,弥补其他依赖本进程服务的周期偏差
try {
Thread.sleep(s * 1000);
} catch (InterruptedException ex) {
}
logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister");
}
}
public int intervalCheckSeconds() {
return 10;
}
//获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段
public abstract CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname);
//获取HTTP远程服务的可用ip列表
public abstract CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname);
//获取远程服务的可用ip列表
protected abstract CompletableFuture<Collection<InetSocketAddress>> queryAddress(ClusterEntry entry);
//注册服务
protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service);
//注销服务
protected abstract void deregister(NodeServer ns, String protocol, Service service);
//格式: protocol:classtype-resourcename
protected void updateSncpTransport(ClusterEntry entry) {
Service service = entry.serviceref.get();
if (service == null) return;
Collection<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netprotocol, entry.address, null, addrs);
}
protected String generateApplicationServiceName() {
return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node" + this.nodeid;
}
protected String generateApplicationServiceId() { //与servicename相同
return generateApplicationServiceName();
}
protected String generateApplicationCheckName() {
return "check-" + generateApplicationServiceName();
}
protected String generateApplicationCheckId() {
return "check-" + generateApplicationServiceId();
}
//也会提供给HttpMessageClusterAgent适用
public String generateHttpServiceName(String protocol, String module, String resname) {
return protocol.toLowerCase() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
}
//格式: protocol:classtype-resourcename
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
if (protocol.toLowerCase().startsWith("http")) { //HTTP使用RestService.name方式是为了与MessageClient中的module保持一致, 因为HTTP依靠的url中的module无法知道Service类名
String resname = Sncp.getResourceName(service);
String module = Rest.getRestModule(service).toLowerCase();
return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname));
}
if ("mqtp".equalsIgnoreCase(protocol)) {
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
String selfmodule = Rest.getRestModule(service).toLowerCase();
return protocol.toLowerCase() + ":" + mmc.module() + ":" + selfmodule;
}
if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName();
String resname = Sncp.getResourceName(service);
return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname));
}
//格式: protocol:classtype-resourcename:nodeid
protected String generateServiceId(NodeServer ns, String protocol, Service service) {
return generateServiceName(ns, protocol, service) + ":" + this.nodeid;
}
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
return "check-" + generateServiceName(ns, protocol, service);
}
protected String generateCheckId(NodeServer ns, String protocol, Service service) {
return "check-" + generateServiceId(ns, protocol, service);
}
protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() {
return localEntrys;
}
protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() {
return remoteEntrys;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
public TransportFactory getTransportFactory() {
return transportFactory;
}
public void setTransportFactory(TransportFactory transportFactory) {
this.transportFactory = transportFactory;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getProtocols() {
return protocols;
}
public void setProtocols(String[] protocols) {
this.protocols = protocols;
}
public int[] getPorts() {
return ports;
}
public void setPorts(int[] ports) {
this.ports = ports;
}
public AnyValue getConfig() {
return config;
}
public void setConfig(AnyValue config) {
this.config = config;
}
public class ClusterEntry {
public String serviceid;
public String servicename;
public String checkid;
public String checkname;
public String protocol;
public String netprotocol;
public WeakReference<Service> serviceref;
public InetSocketAddress address;
public boolean canceled;
public boolean submqtp;
public ClusterEntry(NodeServer ns, String protocol, Service service) {
this.serviceid = generateServiceId(ns, protocol, service);
this.servicename = generateServiceName(ns, protocol, service);
this.checkid = generateCheckId(ns, protocol, service);
this.checkname = generateCheckName(ns, protocol, service);
this.protocol = protocol;
InetSocketAddress addr = ns.getSocketAddress();
String host = addr.getHostString();
if ("0.0.0.0".equals(host)) {
host = appAddress.getHostString();
addr = new InetSocketAddress(host, addr.getPort());
}
this.address = addr;
this.serviceref = new WeakReference(service);
Server server = ns.getServer();
this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}
}

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.cluster;
import org.redkale.util.AnyValue;
/**
* 自定义的ClusterAgent加载器
*
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.5.0
*/
public interface ClusterAgentProvider {
public boolean acceptsConf(AnyValue config);
public Class<? extends ClusterAgent> agentClass();
}

View File

@@ -0,0 +1,69 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import java.util.*;
import org.redkale.util.*;
import org.redkale.convert.Reader.ValueType;
import static org.redkale.convert.Reader.ValueType.MAP;
/**
* 对不明类型的对象进行反序列化。 <br>
* <b>注意: 目前只支持文本格式</b> <br>
*
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class AnyDecoder implements Decodeable<Reader, Object> {
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
}.getType();
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
}.getType();
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
final Decodeable<Reader, String> stringDecoder;
final CollectionDecoder collectionDecoder;
final MapDecoder mapDecoder;
/**
* 构造函数
*
* @param factory ConvertFactory
*/
public AnyDecoder(final ConvertFactory factory) {
this.stringDecoder = factory.loadDecoder(String.class);
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
}
@Override
public Object convertFrom(Reader in) {
ValueType vt = in.readType();
if (vt == null) return null;
switch (vt) {
case ARRAY:
return this.collectionDecoder.convertFrom(in);
case MAP:
return this.mapDecoder.convertFrom(in);
}
return this.stringDecoder.convertFrom(in);
}
@Override
public Type getType() {
return void.class;
}
}

View File

@@ -6,11 +6,10 @@
package org.redkale.convert;
import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;
/**
* 对不明类型的对象进行序列化 BSON序列化时将对象的类名写入WriterJSON则不写入
* <p>
*
* 详情见: https://redkale.org
*
* @author zhangjx
@@ -31,30 +30,14 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
out.writeClassName(null);
out.writeNull();
} else {
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(value.getClass()));
factory.loadEncoder(value.getClass()).convertTo(out, value);
}
}
@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);
}
Class clazz = value.getClass();
if (clazz == Object.class) {
out.writeObjectB(value);
out.writeObjectE(value);
return;
}
out.writeMapE();
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clazz));
factory.loadEncoder(clazz).convertTo(out, value);
}
}

View File

@@ -0,0 +1,40 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import org.redkale.util.AnyValue;
/**
* AnyValue的Decoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
*
* @since 2.5.0
*/
public class AnyValueDecoder<R extends Reader> implements Decodeable<R, AnyValue> {
protected final ConvertFactory factory;
public AnyValueDecoder(final ConvertFactory factory) {
this.factory = factory;
}
@Override
public AnyValue convertFrom(R in) {
return null;
}
@Override
public Type getType() {
return AnyValue.class;
}
}

View File

@@ -0,0 +1,33 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import org.redkale.util.AnyValue;
/**
* AnyValue的Encoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <W> Writer输出的子类
*
* @since 2.5.0
*/
public class AnyValueEncoder<W extends Writer> implements Encodeable<W, AnyValue> {
@Override
public void convertTo(W out, AnyValue value) {
}
@Override
public Type getType() {
return AnyValue.class;
}
}

View File

@@ -20,19 +20,19 @@ import java.util.*;
* @param <T> 反解析的数组元素类型
*/
@SuppressWarnings("unchecked")
public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
private final Class componentClass;
protected final Class componentClass;
protected final Decodeable<Reader, T> decoder;
protected final Decodeable<Reader, T> componentDecoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -51,7 +51,7 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
this.componentClass = (Class) this.componentType;
}
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
this.componentDecoder = factory.loadDecoder(this.componentType);
} finally {
inited = true;
synchronized (lock) {
@@ -62,9 +62,19 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
@Override
public T[] convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public T[] convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -75,11 +85,16 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final List<T> result = new ArrayList();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -91,9 +106,26 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
return result.toArray(rs);
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder;
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
if (in == null) return null;
return decoder.convertFrom(in);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}";
}
@Override
@@ -101,4 +133,12 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder;
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.*;
/**
* 数组的序列化操作类 <br>
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 <br>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 序列化的数组元素类型
*/
@SuppressWarnings("unchecked")
public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
protected final Type type;
protected final Type componentType;
protected final Encodeable anyEncoder;
protected final Encodeable<Writer, Object> componentEncoder;
protected final boolean subtypefinal;
protected volatile boolean inited = false;
protected final Object lock = new Object();
public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {
if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType();
} else {
throw new ConvertException("(" + type + ") is not a array type");
}
factory.register(type, this);
this.componentEncoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder();
this.subtypefinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers());
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@Override
public void convertTo(Writer out, T[] value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, T[] value) {
if (value == null) {
out.writeNull();
return;
}
int iMax = value.length - 1;
if (iMax == -1) {
out.writeArrayB(0, this, componentEncoder, value);
out.writeArrayE();
return;
}
if (this.componentEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Encodeable<Writer, Object> itemEncoder = this.componentEncoder;
if (subtypefinal) {
if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) {
for (int i = 0;; i++) {
writeMemberValue(out, member, itemEncoder, value[i], i);
if (i == iMax) break;
out.writeArrayMark();
}
}
} else {
if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) {
final Type comp = this.componentType;
for (int i = 0;; i++) {
Object v = value[i];
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? itemEncoder : anyEncoder), v, i);
if (i == iMax) break;
out.writeArrayMark();
}
}
}
out.writeArrayE();
}
protected void writeMemberValue(Writer out, EnMember member, Encodeable<Writer, Object> encoder, Object value, int index) {
encoder.convertTo(out, value);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}";
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder;
}
}

View File

@@ -32,5 +32,4 @@ public abstract class BinaryConvert<R extends Reader, W extends Writer> extends
public abstract byte[] convertTo(final Type type, final Object value);
public abstract byte[] convertMapTo(final Object... values);
}

View File

@@ -0,0 +1,149 @@
/*
* 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.*;
/**
* Collection的反序列化操作类 <br>
* 支持一定程度的泛型。 <br>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 反解析的集合元素类型
*/
@SuppressWarnings("unchecked")
public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
protected final Type type;
protected final Type componentType;
protected Creator<Collection<T>> creator;
protected final Decodeable<Reader, T> componentDecoder;
protected volatile boolean inited = false;
protected final Object lock = new Object();
public CollectionDecoder(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.componentDecoder = factory.loadDecoder(this.componentType);
} else if (factory.isReversible()) {
this.componentType = Object.class;
this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class);
factory.register(type, this);
this.componentDecoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("CollectionDecoder not support the type (" + type + ")");
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
//仅供类似JsonAnyDecoder这种动态创建使用 不得调用 factory.register
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
Objects.requireNonNull(componentDecoder);
this.type = type;
this.componentType = componentType;
this.creator = creator;
this.componentDecoder = componentDecoder;
this.inited = true;
}
@Override
public Collection<T> convertFrom(Reader in) {
return convertFrom(in, null);
}
public Collection<T> convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final Collection<T> result = this.creator.create();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
result.add(localdecoder.convertFrom(in));
}
}
in.readArrayE();
return result;
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder;
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
if (in == null) return null;
return decoder.convertFrom(in);
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder;
}
}

View File

@@ -19,15 +19,15 @@ import java.util.Collection;
* @param <T> 序列化的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
private final Type type;
protected final Type type;
private final Encodeable<Writer, Object> encoder;
protected final Encodeable<Writer, Object> componentEncoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -35,12 +35,12 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
this.componentEncoder = factory.getAnyEncoder();
} else {
this.encoder = factory.loadEncoder(t);
this.componentEncoder = factory.loadEncoder(t);
}
} else {
this.encoder = factory.getAnyEncoder();
this.componentEncoder = factory.getAnyEncoder();
}
} finally {
inited = true;
@@ -52,16 +52,20 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
@Override
public void convertTo(Writer out, Collection<T> value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, Collection<T> value) {
if (value == null) {
out.writeNull();
return;
}
if (value.isEmpty()) {
out.writeArrayB(0);
out.writeArrayB(0, this, componentEncoder, value);
out.writeArrayE();
return;
}
if (this.encoder == null) {
if (this.componentEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -72,18 +76,36 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
}
}
}
out.writeArrayB(value.size());
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
encoder.convertTo(out, v);
if (first) first = false;
if (out.writeArrayB(value.size(), this, componentEncoder, value) < 0) {
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, v, first);
if (first) first = false;
}
}
out.writeArrayE();
}
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
componentEncoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}";
}
public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder;
}
public Type getComponentType() {
return componentEncoder == null ? null : componentEncoder.getType();
}
}

View File

@@ -0,0 +1,80 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.util.function.*;
import org.redkale.util.*;
/**
* 序列化/反序列化操作类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
public abstract class Convert<R extends Reader, W extends Writer> {
protected final ConvertFactory<R, W> factory;
protected Convert(ConvertFactory<R, W> factory) {
this.factory = factory;
}
public ConvertFactory<R, W> getFactory() {
return this.factory;
}
protected <S extends W> S configWrite(S writer) {
return writer;
}
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
writer.objFieldFunc = objFieldFunc;
writer.objExtFunc = objExtFunc;
return writer;
}
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
public abstract boolean isBinary();
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
//@since 2.2.0
public abstract <T> T convertFrom(final Type type, final byte[] bytes, final int offset, final int length);
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 void convertTo(final W writer, final Object value);
public abstract void convertTo(final W writer, final Type type, final Object value);
public abstract byte[] convertToBytes(final Object value);
public abstract byte[] convertToBytes(final Type type, final Object value);
public abstract void convertToBytes(final Object value, final ConvertBytesHandler handler);
public abstract void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler);
public abstract void convertToBytes(final ByteArray array, final Object value);
public abstract void convertToBytes(final ByteArray array, final Type type, final Object value);
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);
}

View File

@@ -0,0 +1,23 @@
/*
* 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.util.function.Consumer;
/**
*
* convertToBytes系列的方法的回调
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.3.0
*/
public interface ConvertBytesHandler {
<A> void completed(byte[] bs, int offset, int length, Consumer<A> callback, A attachment);
}

View File

@@ -89,4 +89,9 @@ public final class ConvertColumnEntry {
this.index = index;
}
@Override
public String toString() {
return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}';
}
}

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