Compare commits
587 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75698d9390 | ||
|
|
9d343694cc | ||
|
|
fddb2a3be0 | ||
|
|
3b44eddbb9 | ||
|
|
ba4100e22d | ||
|
|
72155e31dd | ||
|
|
60903c844e | ||
|
|
5c810b5ff6 | ||
|
|
e3a8c2d392 | ||
|
|
1f27d5f3e3 | ||
|
|
abb790da54 | ||
|
|
f4a2f2af94 | ||
|
|
29a21d060b | ||
|
|
de19861974 | ||
|
|
e5766e31dc | ||
|
|
fca727ecaf | ||
|
|
d009c9b2ed | ||
|
|
fd2e84f781 | ||
|
|
2b7676449d | ||
|
|
4b2c6eba63 | ||
|
|
84147280cf | ||
|
|
e62d9f8201 | ||
|
|
4cec4e64f9 | ||
|
|
9eb647428c | ||
|
|
b68808b325 | ||
|
|
a9dce0efbf | ||
|
|
de63f81238 | ||
|
|
a05afe45c0 | ||
|
|
236996caa1 | ||
|
|
b808c93885 | ||
|
|
7865b74359 | ||
|
|
143e1880d4 | ||
|
|
1be467cfe9 | ||
|
|
7f8f157616 | ||
|
|
c140ad6828 | ||
|
|
50e41dba25 | ||
|
|
c73fc5f266 | ||
|
|
a5f3adc477 | ||
|
|
b77764c1cf | ||
|
|
714b188560 | ||
|
|
47315f188a | ||
|
|
384a8a3991 | ||
|
|
7a80c00439 | ||
|
|
43486ce1e2 | ||
|
|
627c1e953e | ||
|
|
da141cc6bd | ||
|
|
8f3a9a6297 | ||
|
|
e8d496b0ad | ||
|
|
f5accfbe8f | ||
|
|
16e291036e | ||
|
|
a79b8b77b5 | ||
|
|
8e2d6acdf8 | ||
|
|
70c5123f7a | ||
|
|
7cfbaee199 | ||
|
|
fa8d78e18f | ||
|
|
4f5e72a31a | ||
|
|
7c5822fb7c | ||
|
|
60df140bfd | ||
|
|
f41e905842 | ||
|
|
9824fe6da3 | ||
|
|
1fb37f4b67 | ||
|
|
a8a6861a21 | ||
|
|
614222bdc3 | ||
|
|
8e98dda795 | ||
|
|
3686306505 | ||
|
|
d29aa78022 | ||
|
|
85fa406e1d | ||
|
|
d501e2016f | ||
|
|
cf0cd66ac9 | ||
|
|
c921f657b1 | ||
|
|
c93c1d84c5 | ||
|
|
2e66b1a546 | ||
|
|
48629146ed | ||
|
|
a6c8502416 | ||
|
|
fc74dc33c1 | ||
|
|
73de9dfc33 | ||
|
|
68d78a4aa4 | ||
|
|
b618e0e884 | ||
|
|
2d1a6e0edc | ||
|
|
76a7e92787 | ||
|
|
a2178b9a5f | ||
|
|
dcf0fecdb0 | ||
|
|
f88db8abf9 | ||
|
|
0c8b0f5e19 | ||
|
|
b794872147 | ||
|
|
86614f035b | ||
|
|
5f3a472c5e | ||
|
|
7eb2a405d3 | ||
|
|
1d030183bb | ||
|
|
d211692306 | ||
|
|
86c7d95c80 | ||
|
|
e99d43b25c | ||
|
|
730fc0a911 | ||
|
|
1ea92d7165 | ||
|
|
0dfc0ca853 | ||
|
|
474f82b3cf | ||
|
|
ae80109c77 | ||
|
|
807fe63cbe | ||
|
|
44ed3259f9 | ||
|
|
93b2b5fab8 | ||
|
|
58e807439c | ||
|
|
ca2f34bfac | ||
|
|
b8719d7f76 | ||
|
|
be0fdd9045 | ||
|
|
1d2b583c0c | ||
|
|
9def35e2e1 | ||
|
|
a11127ea58 | ||
|
|
af80864e08 | ||
|
|
f6a4fbdf87 | ||
|
|
61f48be2a6 | ||
|
|
8516925537 | ||
|
|
f828ec3d08 | ||
|
|
1eb1706166 | ||
|
|
ffd3b6daf6 | ||
|
|
76d538264a | ||
|
|
02d0a06195 | ||
|
|
c43325e402 | ||
|
|
63bc4b2d00 | ||
|
|
6e5da92263 | ||
|
|
6358719255 | ||
|
|
bdfd92299a | ||
|
|
aa4c9896ba | ||
|
|
1549f1feed | ||
|
|
2a9a713f3e | ||
|
|
0377dac71f | ||
|
|
13217a11c0 | ||
|
|
146b81ee5e | ||
|
|
8502792aad | ||
|
|
3d9447327a | ||
|
|
288fc67621 | ||
|
|
d4bc751a20 | ||
|
|
4cf160e5d3 | ||
|
|
98f29d6a6e | ||
|
|
92bb0a561b | ||
|
|
1329f6f0e1 | ||
|
|
a3dbfaba88 | ||
|
|
2032f39bf9 | ||
|
|
8840415739 | ||
|
|
bdf2fd21c3 | ||
|
|
bd1e326404 | ||
|
|
ebd31bc3d3 | ||
|
|
7185191d91 | ||
|
|
1a1dd44f34 | ||
|
|
95fd147268 | ||
|
|
88657fdf63 | ||
|
|
03de684940 | ||
|
|
b445b99572 | ||
|
|
bd4343c5d8 | ||
|
|
a58c13cd9f | ||
|
|
cf23ecc12c | ||
|
|
86754c2324 | ||
|
|
e6f0a8fdf3 | ||
|
|
fa9fc531d0 | ||
|
|
30bf2c1ad3 | ||
|
|
d326da9344 | ||
|
|
8f6494163d | ||
|
|
490cabefb2 | ||
|
|
66ff86d6fb | ||
|
|
0e5479d55e | ||
|
|
3eb3e0104d | ||
|
|
079e6116b2 | ||
|
|
b6a3adb21c | ||
|
|
ecf831c0f5 | ||
|
|
adfa0be79e | ||
|
|
7ec91802b2 | ||
|
|
1e15eb31c7 | ||
|
|
8d5e61a9a2 | ||
|
|
64500b113a | ||
|
|
a7e5fad571 | ||
|
|
531b00b6fd | ||
|
|
ce3fc5792b | ||
|
|
a477b2fb73 | ||
|
|
6a5d121615 | ||
|
|
90960e0574 | ||
|
|
b6980f7cf8 | ||
|
|
2fb3472de0 | ||
|
|
6dacbafc29 | ||
|
|
f1fcbd7396 | ||
|
|
681e389f19 | ||
|
|
06b7274364 | ||
|
|
b4f7de4858 | ||
|
|
6261232ce6 | ||
|
|
eb35b90950 | ||
|
|
958cea4e0d | ||
|
|
7f184bae50 | ||
|
|
3d68103a19 | ||
|
|
612851bce0 | ||
|
|
e365dae9e4 | ||
|
|
b6d5fc02dc | ||
|
|
59d139ace2 | ||
|
|
1d7a72f992 | ||
|
|
45f2ce261e | ||
|
|
f79e49db5a | ||
|
|
218aebaa0f | ||
|
|
f11870d6bc | ||
|
|
ebea6bb92c | ||
|
|
4806d6ada0 | ||
|
|
6909748bda | ||
|
|
982fc8440c | ||
|
|
e4df07a00c | ||
|
|
0ee30aca7e | ||
|
|
b994bcbcfb | ||
|
|
cc23b44409 | ||
|
|
de36ef697d | ||
|
|
e0d224a330 | ||
|
|
adc2106bec | ||
|
|
6cdbe957a7 | ||
|
|
14808cb01c | ||
|
|
1edadbfee8 | ||
|
|
043a23ecdf | ||
|
|
383ef37989 | ||
|
|
9cd9a8d3ea | ||
|
|
db8c94f433 | ||
|
|
22fb3e5bef | ||
|
|
6329722f17 | ||
|
|
2dee61223d | ||
|
|
f83fc52e9c | ||
|
|
2f8a04c15d | ||
|
|
a1501af7a7 | ||
|
|
a1fdfc9cc9 | ||
|
|
2dddf3c2a5 | ||
|
|
84061cf60f | ||
|
|
557c2c7858 | ||
|
|
cb2d355bc9 | ||
|
|
ed1b642d5b | ||
|
|
411f5e1951 | ||
|
|
450506ca96 | ||
|
|
bf700aa88f | ||
|
|
c108ab196c | ||
|
|
cac8662c01 | ||
|
|
197c58ef98 | ||
|
|
d4c2723759 | ||
|
|
c34a6d8f49 | ||
|
|
5de580c00b | ||
|
|
ed1fb151d7 | ||
|
|
4c4913c5d0 | ||
|
|
adb0dc5963 | ||
|
|
740bc8ae31 | ||
|
|
30a0b12020 | ||
|
|
b0b8b0db3b | ||
|
|
71244732f2 | ||
|
|
820af60c19 | ||
|
|
b3252359bd | ||
|
|
9ade568597 | ||
|
|
cf5224a5f6 | ||
|
|
6c4a83d14d | ||
|
|
0439b95139 | ||
|
|
72a618a0b7 | ||
|
|
0f7520e67b | ||
|
|
fcd69474a2 | ||
|
|
3130e00bab | ||
|
|
1c063b57ec | ||
|
|
efeff3b720 | ||
|
|
ea15634f47 | ||
|
|
e744d001c6 | ||
|
|
06e486e5e2 | ||
|
|
95180ffdef | ||
|
|
e5bd85e9aa | ||
|
|
ec4ec2ff77 | ||
|
|
5a1c9215bc | ||
|
|
53457b73ad | ||
|
|
8cb9fcf01a | ||
|
|
2c88b0e75e | ||
|
|
4daffdc31f | ||
|
|
16dec2cde5 | ||
|
|
82e5fb593e | ||
|
|
4a60ecb3ff | ||
|
|
38307405ed | ||
|
|
fe332d0cbd | ||
|
|
e45f75c1d6 | ||
|
|
a77f450757 | ||
|
|
9f8e946ea3 | ||
|
|
7633687665 | ||
|
|
a1e37643d0 | ||
|
|
8440b58d6c | ||
|
|
a97f8efe21 | ||
|
|
d83e7c22ac | ||
|
|
01a5b32b22 | ||
|
|
8834f57582 | ||
|
|
57fd7b96b4 | ||
|
|
14fe2fbc84 | ||
|
|
0b86edb654 | ||
|
|
07ab74902c | ||
|
|
e4c6e860c1 | ||
|
|
02cf587fcf | ||
|
|
081773163b | ||
|
|
292ff63699 | ||
|
|
f1a97c0219 | ||
|
|
e545010034 | ||
|
|
ef57fa9a25 | ||
|
|
1bd0d891a4 | ||
|
|
9a51c1de1d | ||
|
|
e4bb75dd8e | ||
|
|
66e1e08ae2 | ||
|
|
708cd5a644 | ||
|
|
138c9aba97 | ||
|
|
e5e17b4496 | ||
|
|
cadaebefb9 | ||
|
|
e2fb7935f6 | ||
|
|
16b3dab600 | ||
|
|
758972890e | ||
|
|
a88285d935 | ||
|
|
d7832fb931 | ||
|
|
f073c9a0bc | ||
|
|
63ef83ec62 | ||
|
|
51c50415e1 | ||
|
|
2f08fa6476 | ||
|
|
3091972fc5 | ||
|
|
8e14df9a95 | ||
|
|
683cec6f4d | ||
|
|
ec6e5aa3b1 | ||
|
|
f4c00a9b6f | ||
|
|
c071ec5d6c | ||
|
|
29148c4b42 | ||
|
|
7340caa4a9 | ||
|
|
7d23dfa73d | ||
|
|
19932820a9 | ||
|
|
6b59c54087 | ||
|
|
58f5ee999a | ||
|
|
32e8c033ea | ||
|
|
84a96f750f | ||
|
|
6560e71e48 | ||
|
|
ee8a18a528 | ||
|
|
c36fc36964 | ||
|
|
a34f85bfc9 | ||
|
|
6f00efa077 | ||
|
|
469dff8478 | ||
|
|
c50eb79b1d | ||
|
|
985bf6ed25 | ||
|
|
bd51696e08 | ||
|
|
2764d59a4f | ||
|
|
c1509bb712 | ||
|
|
b14f32deb3 | ||
|
|
62145a2aad | ||
|
|
8fb88a57b2 | ||
|
|
44f12ae003 | ||
|
|
bf97ef3a08 | ||
|
|
aeefc3b8a2 | ||
|
|
5763718816 | ||
|
|
3b142b7504 | ||
|
|
0f52d32424 | ||
|
|
f5f3c48f38 | ||
|
|
9f9f5aa000 | ||
|
|
be4ca0287b | ||
|
|
a84ed72f28 | ||
|
|
8eb5f56f42 | ||
|
|
df1aa2b379 | ||
|
|
da2befcb97 | ||
|
|
92d0f7e796 | ||
|
|
6aa3949d05 | ||
|
|
fa833d9224 | ||
|
|
c9261f8475 | ||
|
|
a1df62af08 | ||
|
|
aa12413f4e | ||
|
|
2ccd9ba10f | ||
|
|
81ae68c571 | ||
|
|
51b45f4713 | ||
|
|
66e1f58879 | ||
|
|
06bb5180cf | ||
|
|
d83d7f879c | ||
|
|
b8e92c949e | ||
|
|
91548a0ca9 | ||
|
|
dbca25cd54 | ||
|
|
539ea15ae5 | ||
|
|
ad1d9f33d4 | ||
|
|
df98c1a58e | ||
|
|
56d1969c96 | ||
|
|
4b341436af | ||
|
|
4d3d73b4c1 | ||
|
|
55ab279e7f | ||
|
|
82ab994608 | ||
|
|
1c4035e677 | ||
|
|
afdc9e7207 | ||
|
|
9b83abb06a | ||
|
|
26d1a10bd0 | ||
|
|
7e55dcc46d | ||
|
|
45802d2403 | ||
|
|
3660a2a4e5 | ||
|
|
bed81bd93d | ||
|
|
131855cdc5 | ||
|
|
8b69e7d02b | ||
|
|
02a10bf014 | ||
|
|
004b83172e | ||
|
|
fee4555cef | ||
|
|
758bd7de72 | ||
|
|
b2dd366640 | ||
|
|
934c82eadd | ||
|
|
c7ed6574cc | ||
|
|
2ea2667fa7 | ||
|
|
34ae2d38c5 | ||
|
|
a1c95544cb | ||
|
|
c6dc38c35c | ||
|
|
39203ab598 | ||
|
|
51a95a84aa | ||
|
|
8a8d45e642 | ||
|
|
52eb7dbc0c | ||
|
|
0e14b60f12 | ||
|
|
d373ab7204 | ||
|
|
4f9a563ba7 | ||
|
|
852da19b1e | ||
|
|
ddfc040a53 | ||
|
|
df3ccb763a | ||
|
|
f42561ca93 | ||
|
|
580e28519a | ||
|
|
9ecc1d8f19 | ||
|
|
40629ed7b9 | ||
|
|
5790135add | ||
|
|
fd862ed6c6 | ||
|
|
33763af96c | ||
|
|
7c05df3cfb | ||
|
|
f471e2d4c5 | ||
|
|
d4fd093521 | ||
|
|
40003c7789 | ||
|
|
b94f99f338 | ||
|
|
bd21644571 | ||
|
|
5f3599d9b8 | ||
|
|
1e4a30bd70 | ||
|
|
e7dc5de9f2 | ||
|
|
ccb9cb28f5 | ||
|
|
4d9b72c922 | ||
|
|
a51ae13a39 | ||
|
|
dfca186688 | ||
|
|
fadd229a89 | ||
|
|
7acc69adc4 | ||
|
|
d88e4120a1 | ||
|
|
ef98edd91a | ||
|
|
f4548bbe34 | ||
|
|
11a5faca1d | ||
|
|
c37b0e8cb5 | ||
|
|
a20570a6eb | ||
|
|
5e3edb7e1d | ||
|
|
ad8f1d2da6 | ||
|
|
24b23c894f | ||
|
|
c551d5fb81 | ||
|
|
fba43894c1 | ||
|
|
22cc7e086c | ||
|
|
1791008729 | ||
|
|
90e15dd253 | ||
|
|
7db73c076c | ||
|
|
95ad6e99d9 | ||
|
|
0b2a5d0f61 | ||
|
|
b7acce0814 | ||
|
|
8744e76cad | ||
|
|
446b3c13dc | ||
|
|
3951e28148 | ||
|
|
b74d679608 | ||
|
|
edbc878b73 | ||
|
|
f706209ec1 | ||
|
|
bf000b188f | ||
|
|
def1736a9b | ||
|
|
0242f4c0c3 | ||
|
|
5cd399b2df | ||
|
|
9ddb662016 | ||
|
|
2947275d54 | ||
|
|
e43f814872 | ||
|
|
6e16f52e28 | ||
|
|
fca13557df | ||
|
|
824a6df55a | ||
|
|
b98b526c50 | ||
|
|
8f6aa4f4a5 | ||
|
|
00a07a79b2 | ||
|
|
264dfbef2e | ||
|
|
2e27814809 | ||
|
|
f767f40e56 | ||
|
|
543ecc071a | ||
|
|
2a14f39495 | ||
|
|
95c8ae2334 | ||
|
|
338ea13828 | ||
|
|
4a8b9e5fec | ||
|
|
e281cac3d3 | ||
|
|
a495829a3c | ||
|
|
b0deed2a89 | ||
|
|
70a75abf74 | ||
|
|
1aa97f8e79 | ||
|
|
b4000235ac | ||
|
|
4b93f29a1c | ||
|
|
4892a50670 | ||
|
|
2fe0ac0ef9 | ||
|
|
333ae72148 | ||
|
|
5fd5b7f303 | ||
|
|
528cf45f3f | ||
|
|
c7308e7320 | ||
|
|
e2a49eaab7 | ||
|
|
44bd6f235c | ||
|
|
601d15b513 | ||
|
|
9e93485a97 | ||
|
|
ad87b2115d | ||
|
|
27a587d31f | ||
|
|
fc8fa27602 | ||
|
|
f9aebc8ee3 | ||
|
|
1167da8f4c | ||
|
|
7a5fbcdccd | ||
|
|
345e929712 | ||
|
|
358862fe59 | ||
|
|
3dde9bb293 | ||
|
|
99ae4ccadd | ||
|
|
98e9ffe0ef | ||
|
|
6927bfe8ac | ||
|
|
340a3a8fa3 | ||
|
|
4724763991 | ||
|
|
03353ad08c | ||
|
|
95c3354fcd | ||
|
|
1bda2f92b9 | ||
|
|
bd3c706934 | ||
|
|
ef3663aa36 | ||
|
|
427ff717d4 | ||
|
|
b409300412 | ||
|
|
ca1f974dbe | ||
|
|
6a8c86096b | ||
|
|
2b2fd9965b | ||
|
|
0938635eb2 | ||
|
|
a4a186751e | ||
|
|
ea5169b5c5 | ||
|
|
01bd195847 | ||
|
|
a72c26a935 | ||
|
|
a9900d9bfa | ||
|
|
6896401d2d | ||
|
|
886f01c9f3 | ||
|
|
59c9251d70 | ||
|
|
fad5f010d2 | ||
|
|
737c4a92b9 | ||
|
|
d3e8675948 | ||
|
|
a4ffc7a27c | ||
|
|
91bf7b1387 | ||
|
|
1396296337 | ||
|
|
e4672355fc | ||
|
|
129ed25ca4 | ||
|
|
e6d7e5fe98 | ||
|
|
73ce5fa11f | ||
|
|
ce01c3d4ce | ||
|
|
3b3de316ea | ||
|
|
8c739ce54d | ||
|
|
0aa4d6c967 | ||
|
|
d7a3f4d87d | ||
|
|
fe9e074581 | ||
|
|
40813e8752 | ||
|
|
e90f2e4142 | ||
|
|
2a19ea709b | ||
|
|
30c9be303f | ||
|
|
e101b79472 | ||
|
|
8ad919f952 | ||
|
|
294543c46e | ||
|
|
79f8363d47 | ||
|
|
6d3553b0b5 | ||
|
|
403ab4e281 | ||
|
|
87e7c43032 | ||
|
|
a321b41699 | ||
|
|
fea34863e3 | ||
|
|
bcaf7ab73e | ||
|
|
b9d7eaee1b | ||
|
|
d605045858 | ||
|
|
cf2ab617c2 | ||
|
|
204514cb08 | ||
|
|
cfe01cca75 | ||
|
|
ac294c58ae | ||
|
|
6950eb2f30 | ||
|
|
847f81374b | ||
|
|
bb09aea8bb | ||
|
|
2e1ff333f5 | ||
|
|
c14a2b4011 | ||
|
|
d9c6c3d2d0 | ||
|
|
91d4477ed9 | ||
|
|
623c0a127e | ||
|
|
bc64666700 | ||
|
|
5c7dd7d782 | ||
|
|
e78a2da6c0 | ||
|
|
065be6f3d7 | ||
|
|
874f3330b8 | ||
|
|
684edfa10b | ||
|
|
e69a120965 | ||
|
|
4a36244294 | ||
|
|
cb444be0f7 | ||
|
|
8b5cbf186f | ||
|
|
dbc6f8a196 | ||
|
|
9b94604166 | ||
|
|
cc98a85711 | ||
|
|
6855d06f55 | ||
|
|
89d90ddf5b | ||
|
|
6280111121 | ||
|
|
231d41c15f | ||
|
|
cfca7adc66 | ||
|
|
aedd215de4 | ||
|
|
df8e839580 | ||
|
|
300441b9f7 | ||
|
|
1a5e9022ae | ||
|
|
2a3b8f87d3 | ||
|
|
b7930f1ed7 |
@@ -19,8 +19,6 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
编译RedKale 1.8.x版本需要在源码工程中的编译器选项中加入: <b>-XDignore.symbol.file=true</b>
|
|
||||||
|
|
||||||
<h5>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
|
<h5>详情请访问: <a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
|
||||||
|
|
||||||
<h5>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
|
<h5>基本文档: <a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
|
||||||
|
|||||||
7
bin/command.bat
Normal file
7
bin/command.bat
Normal 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
23
bin/command.sh
Normal 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
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<application port="2121">
|
<application nodeid="10" port="2121">
|
||||||
|
|
||||||
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
|
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
</request>
|
</request>
|
||||||
|
|
||||||
<response>
|
<response>
|
||||||
<defcookie domain="" path=""/>
|
<defcookie domain="" path="/"/>
|
||||||
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
||||||
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
||||||
</response>
|
</response>
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>
|
|
||||||
@@ -16,10 +16,6 @@
|
|||||||
<directory>${project.basedir}/conf</directory>
|
<directory>${project.basedir}/conf</directory>
|
||||||
<outputDirectory>conf</outputDirectory>
|
<outputDirectory>conf</outputDirectory>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
|
||||||
<directory>${project.basedir}/libs</directory>
|
|
||||||
<outputDirectory>libs</outputDirectory>
|
|
||||||
</fileSet>
|
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<directory>${project.basedir}/logs</directory>
|
<directory>${project.basedir}/logs</directory>
|
||||||
<outputDirectory>logs</outputDirectory>
|
<outputDirectory>logs</outputDirectory>
|
||||||
|
|||||||
12
my/pom.xml
12
my/pom.xml
@@ -61,13 +61,12 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5.1</version>
|
<version>3.8.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<compilerArgument>-parameters</compilerArgument>
|
<compilerArgument>-parameters</compilerArgument>
|
||||||
<encoding>UTF-8</encoding>
|
<encoding>UTF-8</encoding>
|
||||||
<compilerArguments>
|
<compilerArguments>
|
||||||
<verbose />
|
<verbose />
|
||||||
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
|
|
||||||
</compilerArguments>
|
</compilerArguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
@@ -75,9 +74,10 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.6</version>
|
<version>3.2.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
|
<addMavenDescriptor>false</addMavenDescriptor>
|
||||||
<manifest>
|
<manifest>
|
||||||
<mainClass>org.redkale.boot.Application</mainClass>
|
<mainClass>org.redkale.boot.Application</mainClass>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>3.2.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>2.10.3</version>
|
<version>3.2.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>3.2.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<appendAssemblyId>false</appendAssemblyId>
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
<descriptors>
|
<descriptors>
|
||||||
|
|||||||
@@ -19,11 +19,13 @@
|
|||||||
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
|
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的端口,用于关闭或者与监管系统进行数据交互
|
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="">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
【节点全局唯一】
|
【节点全局唯一】
|
||||||
@@ -34,21 +36,61 @@
|
|||||||
<!--
|
<!--
|
||||||
【节点全局唯一】
|
【节点全局唯一】
|
||||||
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
||||||
threads: 线程总数, 默认: <group>节点数*CPU核数*2
|
threads: 线程总数, 默认: <group>节点数*CPU核数*2
|
||||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 32K;
|
bufferCapacity: ByteBuffer的初始化大小, 默认: 32K;
|
||||||
bufferPoolSize: ByteBuffer池的大小,默认: 线程总数*4
|
bufferPoolSize: ByteBuffer池的大小,默认: 线程总数*4
|
||||||
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒, 为0表示无超时限制
|
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒, 为0表示无超时限制
|
||||||
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒, 为0表示无超时限制
|
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒, 为0表示无超时限制
|
||||||
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
|
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
|
||||||
-->
|
-->
|
||||||
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSeconds="6" writeTimeoutSeconds="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集群不能重复。
|
||||||
|
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内的进程必须在同一机房或局域网内
|
一个组包含多个node, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
||||||
一个group节点对应一个 Transport 对象。
|
一个group节点对应一个 Transport 对象。
|
||||||
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
||||||
protocol:值范围:UDP TCP, 默认TCP
|
protocol: 值范围:UDP TCP, 默认TCP
|
||||||
subprotocol: 子协议,预留字段。默认值为空
|
|
||||||
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
||||||
-->
|
-->
|
||||||
<group name="" protocol="TCP">
|
<group name="" protocol="TCP">
|
||||||
@@ -63,10 +105,10 @@
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
全局的数据源设置, 可以是CacheSource、DataSource, JDBC的DataSource通常通过persistence.xml配置,此处多用于CacheSource的配置
|
全局的数据源设置, 可以是CacheSource、DataSource, JDBC的DataSource通常通过persistence.xml配置,此处多用于CacheSource的配置
|
||||||
name: 资源名,用于依赖注入。
|
name: 资源名,用于依赖注入。
|
||||||
value:类名,必须是CacheSource或DataSource的子类,且必须实现Service接口。如果是DataSource.class,系统自动映射成DataJdbcSource.class
|
value: 类名,必须是CacheSource或DataSource的子类,且必须实现Service接口。如果是DataSource.class,系统自动映射成DataJdbcSource.class
|
||||||
groups: 指定groups。
|
groups: 指定groups。
|
||||||
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
|
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
|
||||||
-->
|
-->
|
||||||
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
|
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
|
||||||
<node addr="127.0.0.1" port="7070"/>
|
<node addr="127.0.0.1" port="7070"/>
|
||||||
@@ -107,35 +149,35 @@
|
|||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
<!--
|
<!--
|
||||||
protocol: required server所启动的协议,Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
|
protocol: required server所启动的协议,Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
|
||||||
name: 服务的名称,用于监控识别,一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
|
name: 服务的名称,用于监控识别,一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
|
||||||
host: 服务所占address , 默认: 0.0.0.0
|
host: 服务所占address , 默认: 0.0.0.0
|
||||||
port: required 服务所占端口
|
port: required 服务所占端口
|
||||||
root: 如果是web类型服务,则包含页面 默认:{APP_HOME}/root
|
root: 如果是web类型服务,则包含页面 默认:{APP_HOME}/root
|
||||||
lib: server额外的class目录, 默认为${APP_HOME}/libs/*;
|
lib: server额外的class目录, 默认为${APP_HOME}/libs/*;
|
||||||
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||||
charset: 文本编码, 默认: UTF-8
|
charset: 文本编码, 默认: UTF-8
|
||||||
backlog: 默认10K
|
backlog: 默认10K
|
||||||
threads: 线程数, 默认: CPU核数*32
|
threads: 线程数, 默认: CPU核数*2,最小8个
|
||||||
maxconns:最大连接数, 小于1表示无限制, 默认: 0
|
maxconns: 最大连接数, 小于1表示无限制, 默认: 0
|
||||||
maxbody: request.body最大值, 默认: 64K
|
maxbody: request.body最大值, 默认: 64K
|
||||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 32K; (HTTP 2.0、WebSocket,必须要16k以上)
|
bufferCapacity: ByteBuffer的初始化大小, TCP默认: 32K; (HTTP 2.0、WebSocket,必须要16k以上); UDP默认: 1350B
|
||||||
bufferPoolSize: ByteBuffer池的大小,默认: 线程数*4
|
bufferPoolSize: ByteBuffer池的大小,默认: 线程数*4
|
||||||
responsePoolSize: Response池的大小,默认: 线程数*2
|
responsePoolSize: Response池的大小,默认: 线程数*2
|
||||||
aliveTimeoutSeconds: KeepAlive读操作超时秒数, 默认30, 0表示永久不超时; -1表示禁止KeepAlive
|
aliveTimeoutSeconds: KeepAlive读操作超时秒数, 默认30, 0表示永久不超时; -1表示禁止KeepAlive
|
||||||
readTimeoutSeconds: 读操作超时秒数, 默认0, 表示永久不超时
|
readTimeoutSeconds: 读操作超时秒数, 默认0, 表示永久不超时
|
||||||
writeTimeoutSeconds: 写操作超时秒数, 默认0, 表示永久不超时
|
writeTimeoutSeconds: 写操作超时秒数, 默认0, 表示永久不超时
|
||||||
netimpl: ProtocolServer的实现类。TCP情况下值可以是aio或nio,默认值为aio;UDP情况下值可以是bio,默认值为bio;
|
netimpl: ProtocolServer的实现类。TCP情况下值可以是aio或nio,默认值为aio;UDP情况下值可以是bio,默认值为bio;
|
||||||
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类,必须是org.redkale.boot.NodeInterceptor的子类,默认为null
|
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类,必须是org.redkale.boot.NodeInterceptor的子类,默认为null
|
||||||
-->
|
-->
|
||||||
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
|
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
【节点在<server>中唯一】
|
【节点在<server>中唯一】
|
||||||
value: 创建SSLContext的实现类, 可自定义,必须是org.redkale.net.SSLCreator的子类
|
value: 创建SSLContext的实现类, 可自定义,必须是org.redkale.net.SSLCreator的子类
|
||||||
clientauth: true/false/want
|
clientauth: true/false/want
|
||||||
keystorepass: KEY密码
|
keystorepass: KEY密码
|
||||||
keystorefile: KEY文件
|
keystorefile: KEY文件
|
||||||
truststorepass: TRUST密码
|
truststorepass: TRUST密码
|
||||||
truststorefile: TRUST文件
|
truststorefile: TRUST文件
|
||||||
-->
|
-->
|
||||||
@@ -146,11 +188,13 @@
|
|||||||
在同一个进程中同一个name同一类型的Service将共用同一个实例
|
在同一个进程中同一个name同一类型的Service将共用同一个实例
|
||||||
autoload="true" 默认值. 自动加载classpath下所有的Service类
|
autoload="true" 默认值. 自动加载classpath下所有的Service类
|
||||||
autoload="false" 需要显著的指定Service类
|
autoload="false" 需要显著的指定Service类
|
||||||
|
mq: 所属的MQ管理器,当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
|
||||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
groups: 所属组的节点,多个节点值用;隔开,如果配置文件中存在多个SNCP协议的Server节点,需要显式指定group属性.
|
groups: 所属组的节点,多个节点值用;隔开,如果配置文件中存在多个SNCP协议的Server节点,需要显式指定group属性.
|
||||||
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
|
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
|
||||||
当 protocol != SNCP 时 group只能是空或者一个group的节点值,不能为多个节点值。
|
当 protocol != SNCP 时 group只能是空或者一个group的节点值,不能为多个节点值。
|
||||||
|
特殊值"$cluster", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息
|
||||||
-->
|
-->
|
||||||
<services autoload="true" includes="" excludes="">
|
<services autoload="true" includes="" excludes="">
|
||||||
|
|
||||||
@@ -174,8 +218,8 @@
|
|||||||
加载所有的Filter服务;
|
加载所有的Filter服务;
|
||||||
autoload="true" 默认值.
|
autoload="true" 默认值.
|
||||||
autoload="false" 需要显著的指定Filter类
|
autoload="false" 需要显著的指定Filter类
|
||||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
-->
|
-->
|
||||||
<filters autoload="true" includes="" excludes="">
|
<filters autoload="true" includes="" excludes="">
|
||||||
|
|
||||||
@@ -198,8 +242,9 @@
|
|||||||
<!--
|
<!--
|
||||||
REST的核心配置项
|
REST的核心配置项
|
||||||
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置,系统会自动生成)
|
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置,系统会自动生成)
|
||||||
path: servlet的ContextPath前缀 默认为空
|
path: servlet的ContextPath前缀 默认为空 【注: 开启MQ时,该字段失效】
|
||||||
base: REST服务的BaseServlet,必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
|
base: REST服务的BaseServlet,必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
|
||||||
|
mq: 所属的MQ管理器, 存在该属性表示RestService的请求来自于消息总线 【注: 开启MQ时,path字段失效】
|
||||||
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
|
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
|
||||||
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
@@ -263,21 +308,21 @@
|
|||||||
当Server为HTTP协议时,ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
|
当Server为HTTP协议时,ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
|
||||||
webroot: web资源的根目录, 默认取server节点中的root值
|
webroot: web资源的根目录, 默认取server节点中的root值
|
||||||
servlet: 静态资源HttpServlet的实现,默认使用HttpResourceServlet
|
servlet: 静态资源HttpServlet的实现,默认使用HttpResourceServlet
|
||||||
index : 启始页,默认值:index.html
|
index : 启始页,默认值:index.html
|
||||||
-->
|
-->
|
||||||
<resource-servlet webroot="root" index="index.html">
|
<resource-servlet webroot="root" index="index.html">
|
||||||
<!--
|
<!--
|
||||||
【节点在<resource-servlet>中唯一】
|
【节点在<resource-servlet>中唯一】
|
||||||
资源缓存的配置, 默认存在一个含默认属性的caches节点
|
资源缓存的配置, 默认存在一个含默认属性的caches节点
|
||||||
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存, 单位可以是B、K、M、G,不区分大小写
|
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存, 单位可以是B、K、M、G,不区分大小写
|
||||||
lengthmax: 可缓存的文件大小上限, 默认: 1M(超过1M的文件不会被缓存)
|
lengthmax: 可缓存的文件大小上限, 默认: 1M(超过1M的文件不会被缓存)
|
||||||
watch: 是否监控缓存文件的变化, 默认为false,不监控
|
watch: 是否监控缓存文件的变化, 默认为false,不监控
|
||||||
-->
|
-->
|
||||||
<cache limit="0M" lengthmax="1M" watch="false"/>
|
<cache limit="0M" lengthmax="1M" watch="false"/>
|
||||||
<!--
|
<!--
|
||||||
支持类似nginx中的rewrite, 目前只支持静态资源对静态资源的跳转。
|
支持类似nginx中的rewrite, 目前只支持静态资源对静态资源的跳转。
|
||||||
type: 匹配的类型, 目前只支持location(匹配requestURI), 默认: location
|
type: 匹配的类型, 目前只支持location(匹配requestURI), 默认: location
|
||||||
match: 匹配的正则表达式
|
match: 匹配的正则表达式
|
||||||
forward: 需跳转后的资源链接
|
forward: 需跳转后的资源链接
|
||||||
例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html
|
例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html
|
||||||
-->
|
-->
|
||||||
@@ -285,11 +330,11 @@
|
|||||||
</resource-servlet>
|
</resource-servlet>
|
||||||
<!--
|
<!--
|
||||||
加载所有的Servlet服务;
|
加载所有的Servlet服务;
|
||||||
path: servlet的ContextPath前缀 默认为空
|
path: servlet的ContextPath前缀 默认为空
|
||||||
autoload="true" 默认值. 自动加载classpath下所有的Servlet类
|
autoload="true" 默认值. 自动加载classpath下所有的Servlet类
|
||||||
autoload="false" 需要显著的指定Service类
|
autoload="false" 需要显著的指定Service类
|
||||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
-->
|
-->
|
||||||
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
/** *****************************************************************************
|
|
||||||
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
|
|
||||||
* which accompanies this distribution.
|
|
||||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
* and the Eclipse Distribution License is available at
|
|
||||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Linda DeMichiel - Java Persistence 2.1
|
|
||||||
* Linda DeMichiel - Java Persistence 2.0
|
|
||||||
*
|
|
||||||
***************************************************************************** */
|
|
||||||
package javax.persistence;
|
|
||||||
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import static java.lang.annotation.ElementType.FIELD;
|
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides for the specification of generation strategies for the
|
|
||||||
* values of primary keys.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The <code>GeneratedValue</code> annotation
|
|
||||||
* may be applied to a primary key property or field of an entity or
|
|
||||||
* mapped superclass in conjunction with the {@link Id} annotation.
|
|
||||||
* The use of the <code>GeneratedValue</code> annotation is only
|
|
||||||
* required to be supported for simple primary keys. Use of the
|
|
||||||
* <code>GeneratedValue</code> annotation is not supported for derived
|
|
||||||
* primary keys.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
*
|
|
||||||
* Example 1:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* public Long getId() { return id; }
|
|
||||||
*
|
|
||||||
* Example 2:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* Long id;
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see Id
|
|
||||||
*
|
|
||||||
* @since Java Persistence 1.0
|
|
||||||
*/
|
|
||||||
@Target({METHOD, FIELD})
|
|
||||||
@Retention(RUNTIME)
|
|
||||||
|
|
||||||
public @interface GeneratedValue {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see Column
|
* @see Column
|
||||||
* @see GeneratedValue
|
* see GeneratedValue
|
||||||
*
|
*
|
||||||
* @since Java Persistence 1.0
|
* @since Java Persistence 1.0
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ module org.redkale {
|
|||||||
exports org.redkale.convert.bson;
|
exports org.redkale.convert.bson;
|
||||||
exports org.redkale.convert.ext;
|
exports org.redkale.convert.ext;
|
||||||
exports org.redkale.convert.json;
|
exports org.redkale.convert.json;
|
||||||
|
exports org.redkale.mq;
|
||||||
exports org.redkale.net;
|
exports org.redkale.net;
|
||||||
exports org.redkale.net.http;
|
exports org.redkale.net.http;
|
||||||
exports org.redkale.net.sncp;
|
exports org.redkale.net.sncp;
|
||||||
@@ -30,5 +31,10 @@ module org.redkale {
|
|||||||
exports org.redkale.util;
|
exports org.redkale.util;
|
||||||
exports org.redkale.watch;
|
exports org.redkale.watch;
|
||||||
|
|
||||||
|
uses org.redkale.cluster.ClusterAgent;
|
||||||
|
uses org.redkale.mq.MessageAgent;
|
||||||
|
uses org.redkale.source.CacheSource;
|
||||||
|
uses org.redkale.source.SourceLoader;
|
||||||
|
uses org.redkale.util.ResourceInjectLoader;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -60,8 +60,8 @@ package org.redkale.asm;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A visitor to visit a Java annotation. The methods of this class must be
|
* 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> |
|
* called in the following order: ( <code>visit</code> | <code>visitEnum</code> |
|
||||||
* <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
|
* <code>visitAnnotation</code> | <code>visitArray</code> )* <code>visitEnd</code>.
|
||||||
*
|
*
|
||||||
* @author Eric Bruneton
|
* @author Eric Bruneton
|
||||||
* @author Eugene Kuleshov
|
* @author Eugene Kuleshov
|
||||||
@@ -151,7 +151,7 @@ public abstract class AnnotationVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the nested annotation class.
|
* the class descriptor of the nested annotation class.
|
||||||
* @return a visitor to visit the actual nested annotation value, or
|
* @return a visitor to visit the actual nested annotation value, or
|
||||||
* <tt>null</tt> if this visitor is not interested in visiting this
|
* <code>null</code> if this visitor is not interested in visiting this
|
||||||
* nested annotation. <i>The nested annotation value must be fully
|
* nested annotation. <i>The nested annotation value must be fully
|
||||||
* visited before calling other methods on this annotation
|
* visited before calling other methods on this annotation
|
||||||
* visitor</i>.
|
* visitor</i>.
|
||||||
@@ -172,7 +172,7 @@ public abstract class AnnotationVisitor {
|
|||||||
* @param name
|
* @param name
|
||||||
* the value name.
|
* the value name.
|
||||||
* @return a visitor to visit the actual array value elements, or
|
* @return a visitor to visit the actual array value elements, or
|
||||||
* <tt>null</tt> if this visitor is not interested in visiting these
|
* <code>null</code> if this visitor is not interested in visiting these
|
||||||
* values. The 'name' parameters passed to the methods of this
|
* values. The 'name' parameters passed to the methods of this
|
||||||
* visitor are ignored. <i>All the array values must be visited
|
* visitor are ignored. <i>All the array values must be visited
|
||||||
* before calling other methods on this annotation visitor</i>.
|
* before calling other methods on this annotation visitor</i>.
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ final class AnnotationWriter extends AnnotationVisitor {
|
|||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
|
* <code>true<code> if values are named, <code>false</code> otherwise. Annotation
|
||||||
* writers used for annotation default and annotation arrays use unnamed
|
* writers used for annotation default and annotation arrays use unnamed
|
||||||
* values.
|
* values.
|
||||||
*/
|
*/
|
||||||
@@ -122,13 +122,13 @@ final class AnnotationWriter extends AnnotationVisitor {
|
|||||||
* @param cw
|
* @param cw
|
||||||
* the class writer to which this annotation must be added.
|
* the class writer to which this annotation must be added.
|
||||||
* @param named
|
* @param named
|
||||||
* <tt>true<tt> if values are named, <tt>false</tt> otherwise.
|
* <code>true<code> if values are named, <code>false</code> otherwise.
|
||||||
* @param bv
|
* @param bv
|
||||||
* where the annotation values must be stored.
|
* where the annotation values must be stored.
|
||||||
* @param parent
|
* @param parent
|
||||||
* where the number of annotation values must be stored.
|
* where the number of annotation values must be stored.
|
||||||
* @param offset
|
* @param offset
|
||||||
* where in <tt>parent</tt> the number of annotation values must
|
* where in <code>parent</code> the number of annotation values must
|
||||||
* be stored.
|
* be stored.
|
||||||
*/
|
*/
|
||||||
AnnotationWriter(final ClassWriter cw, final boolean named,
|
AnnotationWriter(final ClassWriter cw, final boolean named,
|
||||||
@@ -354,7 +354,7 @@ final class AnnotationWriter extends AnnotationVisitor {
|
|||||||
* @param typePath
|
* @param typePath
|
||||||
* the path to the annotated type argument, wildcard bound, array
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
* element type, or static inner type within 'typeRef'. May be
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
* <code>null</code> if the annotation targets 'typeRef' as a whole.
|
||||||
* @param out
|
* @param out
|
||||||
* where the type reference and type path must be put.
|
* where the type reference and type path must be put.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class Attribute {
|
|||||||
byte[] value;
|
byte[] value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The next attribute in this attribute list. May be <tt>null</tt>.
|
* The next attribute in this attribute list. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
Attribute next;
|
Attribute next;
|
||||||
|
|
||||||
@@ -92,19 +92,19 @@ class Attribute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <tt>true</tt> if this type of attribute is unknown. The default
|
* Returns <code>true</code> if this type of attribute is unknown. The default
|
||||||
* implementation of this method always returns <tt>true</tt>.
|
* implementation of this method always returns <code>true</code>.
|
||||||
*
|
*
|
||||||
* @return <tt>true</tt> if this type of attribute is unknown.
|
* @return <code>true</code> if this type of attribute is unknown.
|
||||||
*/
|
*/
|
||||||
public boolean isUnknown() {
|
public boolean isUnknown() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <tt>true</tt> if this type of attribute is a code attribute.
|
* Returns <code>true</code> if this type of attribute is a code attribute.
|
||||||
*
|
*
|
||||||
* @return <tt>true</tt> if this type of attribute is a code attribute.
|
* @return <code>true</code> if this type of attribute is a code attribute.
|
||||||
*/
|
*/
|
||||||
public boolean isCodeAttribute() {
|
public boolean isCodeAttribute() {
|
||||||
return false;
|
return false;
|
||||||
@@ -113,7 +113,7 @@ class Attribute {
|
|||||||
/**
|
/**
|
||||||
* Returns the labels corresponding to this 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 <code>null</code> if
|
||||||
* this attribute is not a code attribute that contains labels.
|
* this attribute is not a code attribute that contains labels.
|
||||||
*/
|
*/
|
||||||
protected Label[] getLabels() {
|
protected Label[] getLabels() {
|
||||||
@@ -123,7 +123,7 @@ class Attribute {
|
|||||||
/**
|
/**
|
||||||
* Reads a {@link #type type} attribute. This method must return a
|
* Reads a {@link #type type} attribute. This method must return a
|
||||||
* <i>new</i> {@link Attribute} object, of type {@link #type type},
|
* <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 <code>len</code> bytes starting at the given offset, in
|
||||||
* the given class reader.
|
* the given class reader.
|
||||||
*
|
*
|
||||||
* @param cr
|
* @param cr
|
||||||
@@ -146,7 +146,7 @@ class Attribute {
|
|||||||
* containing the type and the length of the attribute, are not
|
* containing the type and the length of the attribute, are not
|
||||||
* taken into account here.
|
* taken into account here.
|
||||||
* @param labels
|
* @param labels
|
||||||
* the labels of the method's code, or <tt>null</tt> if the
|
* the labels of the method's code, or <code>null</code> if the
|
||||||
* attribute to be read is not a code attribute.
|
* attribute to be read is not a code attribute.
|
||||||
* @return a <i>new</i> {@link Attribute} object corresponding to the given
|
* @return a <i>new</i> {@link Attribute} object corresponding to the given
|
||||||
* bytes.
|
* bytes.
|
||||||
@@ -169,11 +169,11 @@ class Attribute {
|
|||||||
* class the items that corresponds to this attribute.
|
* class the items that corresponds to this attribute.
|
||||||
* @param code
|
* @param code
|
||||||
* the bytecode of the method corresponding to this code
|
* the bytecode of the method corresponding to this code
|
||||||
* attribute, or <tt>null</tt> if this attribute is not a code
|
* attribute, or <code>null</code> if this attribute is not a code
|
||||||
* attributes.
|
* attributes.
|
||||||
* @param len
|
* @param len
|
||||||
* the length of the bytecode of the method corresponding to this
|
* 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 <code>null</code> if this attribute is not a
|
||||||
* code attribute.
|
* code attribute.
|
||||||
* @param maxStack
|
* @param maxStack
|
||||||
* the maximum stack size of the method corresponding to this
|
* the maximum stack size of the method corresponding to this
|
||||||
@@ -216,11 +216,11 @@ class Attribute {
|
|||||||
* byte arrays, with the {@link #write write} method.
|
* byte arrays, with the {@link #write write} method.
|
||||||
* @param code
|
* @param code
|
||||||
* the bytecode of the method corresponding to these code
|
* the bytecode of the method corresponding to these code
|
||||||
* attributes, or <tt>null</tt> if these attributes are not code
|
* attributes, or <code>null</code> if these attributes are not code
|
||||||
* attributes.
|
* attributes.
|
||||||
* @param len
|
* @param len
|
||||||
* the length of the bytecode of the method corresponding to
|
* the length of the bytecode of the method corresponding to
|
||||||
* these code attributes, or <tt>null</tt> if these attributes
|
* these code attributes, or <code>null</code> if these attributes
|
||||||
* are not code attributes.
|
* are not code attributes.
|
||||||
* @param maxStack
|
* @param maxStack
|
||||||
* the maximum stack size of the method corresponding to these
|
* the maximum stack size of the method corresponding to these
|
||||||
@@ -254,11 +254,11 @@ class Attribute {
|
|||||||
* byte arrays, with the {@link #write write} method.
|
* byte arrays, with the {@link #write write} method.
|
||||||
* @param code
|
* @param code
|
||||||
* the bytecode of the method corresponding to these code
|
* the bytecode of the method corresponding to these code
|
||||||
* attributes, or <tt>null</tt> if these attributes are not code
|
* attributes, or <code>null</code> if these attributes are not code
|
||||||
* attributes.
|
* attributes.
|
||||||
* @param len
|
* @param len
|
||||||
* the length of the bytecode of the method corresponding to
|
* the length of the bytecode of the method corresponding to
|
||||||
* these code attributes, or <tt>null</tt> if these attributes
|
* these code attributes, or <code>null</code> if these attributes
|
||||||
* are not code attributes.
|
* are not code attributes.
|
||||||
* @param maxStack
|
* @param maxStack
|
||||||
* the maximum stack size of the method corresponding to these
|
* the maximum stack size of the method corresponding to these
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ public class ByteVector {
|
|||||||
* automatically enlarged if necessary.
|
* automatically enlarged if necessary.
|
||||||
*
|
*
|
||||||
* @param b
|
* @param b
|
||||||
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
|
* an array of bytes. May be <code>null</code> to put <code>len</code>
|
||||||
* null bytes into this byte vector.
|
* null bytes into this byte vector.
|
||||||
* @param off
|
* @param off
|
||||||
* index of the fist byte of b that must be copied.
|
* index of the fist byte of b that must be copied.
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ public class ClassReader {
|
|||||||
* {@link Type#getInternalName() getInternalName}). For interfaces, the
|
* {@link Type#getInternalName() getInternalName}). For interfaces, the
|
||||||
* super class is {@link Object}.
|
* 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 <code>null</code> for
|
||||||
* {@link Object} class.
|
* {@link Object} class.
|
||||||
*
|
*
|
||||||
* @see ClassVisitor#visit(int, int, String, String, String, String[])
|
* @see ClassVisitor#visit(int, int, String, String, String, String[])
|
||||||
@@ -281,7 +281,7 @@ public class ClassReader {
|
|||||||
* {@link Type#getInternalName() getInternalName}).
|
* {@link Type#getInternalName() getInternalName}).
|
||||||
*
|
*
|
||||||
* @return the array of internal names for all implemented interfaces or
|
* @return the array of internal names for all implemented interfaces or
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*
|
*
|
||||||
* @see ClassVisitor#visit(int, int, String, String, String, String[])
|
* @see ClassVisitor#visit(int, int, String, String, String, String[])
|
||||||
*/
|
*/
|
||||||
@@ -1932,7 +1932,7 @@ public class ClassReader {
|
|||||||
* @param v
|
* @param v
|
||||||
* start offset in {@link #b b} of the annotations to be read.
|
* start offset in {@link #b b} of the annotations to be read.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotations to be read are visible at
|
* <code>true</code> if the annotations to be read are visible at
|
||||||
* runtime.
|
* runtime.
|
||||||
*/
|
*/
|
||||||
private void readParameterAnnotations(final MethodVisitor mv,
|
private void readParameterAnnotations(final MethodVisitor mv,
|
||||||
@@ -2474,9 +2474,9 @@ public class ClassReader {
|
|||||||
* and the length of the attribute, are not taken into account
|
* and the length of the attribute, are not taken into account
|
||||||
* here.
|
* here.
|
||||||
* @param labels
|
* @param labels
|
||||||
* the labels of the method's code, or <tt>null</tt> if the
|
* the labels of the method's code, or <code>null</code> if the
|
||||||
* attribute to be read is not a code attribute.
|
* 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 <code>null</code> to skip this
|
||||||
* attribute.
|
* attribute.
|
||||||
*/
|
*/
|
||||||
private Attribute readAttribute(final Attribute[] attrs, final String type,
|
private Attribute readAttribute(final Attribute[] attrs, final String type,
|
||||||
|
|||||||
@@ -60,11 +60,11 @@ package org.redkale.asm;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A visitor to visit a Java class. The methods of this class must be called in
|
* 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> ] [
|
* the following order: <code>visit</code> [ <code>visitSource</code> ] [
|
||||||
* <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
|
* <code>visitModule</code> ][ <code>visitOuterClass</code> ] ( <code>visitAnnotation</code> |
|
||||||
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
|
* <code>visitTypeAnnotation</code> | <code>visitAttribute</code> )* (
|
||||||
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
|
* <code>visitInnerClass</code> | <code>visitField</code> | <code>visitMethod</code> )*
|
||||||
* <tt>visitEnd</tt>.
|
* <code>visitEnd</code>.
|
||||||
*
|
*
|
||||||
* @author Eric Bruneton
|
* @author Eric Bruneton
|
||||||
*/
|
*/
|
||||||
@@ -120,18 +120,18 @@ public abstract class ClassVisitor {
|
|||||||
* the internal name of the class (see
|
* the internal name of the class (see
|
||||||
* {@link Type#getInternalName() getInternalName}).
|
* {@link Type#getInternalName() getInternalName}).
|
||||||
* @param signature
|
* @param signature
|
||||||
* the signature of this class. May be <tt>null</tt> if the class
|
* the signature of this class. May be <code>null</code> if the class
|
||||||
* is not a generic one, and does not extend or implement generic
|
* is not a generic one, and does not extend or implement generic
|
||||||
* classes or interfaces.
|
* classes or interfaces.
|
||||||
* @param superName
|
* @param superName
|
||||||
* the internal of name of the super class (see
|
* the internal of name of the super class (see
|
||||||
* {@link Type#getInternalName() getInternalName}). For
|
* {@link Type#getInternalName() getInternalName}). For
|
||||||
* interfaces, the super class is {@link Object}. May be
|
* interfaces, the super class is {@link Object}. May be
|
||||||
* <tt>null</tt>, but only for the {@link Object} class.
|
* <code>null</code>, but only for the {@link Object} class.
|
||||||
* @param interfaces
|
* @param interfaces
|
||||||
* the internal names of the class's interfaces (see
|
* the internal names of the class's interfaces (see
|
||||||
* {@link Type#getInternalName() getInternalName}). May be
|
* {@link Type#getInternalName() getInternalName}). May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public void visit(int version, int access, String name, String signature,
|
public void visit(int version, int access, String name, String signature,
|
||||||
String superName, String[] interfaces) {
|
String superName, String[] interfaces) {
|
||||||
@@ -145,11 +145,11 @@ public abstract class ClassVisitor {
|
|||||||
*
|
*
|
||||||
* @param source
|
* @param source
|
||||||
* the name of the source file from which the class was compiled.
|
* the name of the source file from which the class was compiled.
|
||||||
* May be <tt>null</tt>.
|
* May be <code>null</code>.
|
||||||
* @param debug
|
* @param debug
|
||||||
* additional debug information to compute the correspondance
|
* additional debug information to compute the correspondance
|
||||||
* between source and compiled elements of the class. May be
|
* between source and compiled elements of the class. May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public void visitSource(String source, String debug) {
|
public void visitSource(String source, String debug) {
|
||||||
if (cv != null) {
|
if (cv != null) {
|
||||||
@@ -166,7 +166,7 @@ public abstract class ClassVisitor {
|
|||||||
* and {@code ACC_MANDATED}.
|
* and {@code ACC_MANDATED}.
|
||||||
* @param version
|
* @param version
|
||||||
* module version or null.
|
* module version or null.
|
||||||
* @return a visitor to visit the module values, or <tt>null</tt> if
|
* @return a visitor to visit the module values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this module.
|
* this visitor is not interested in visiting this module.
|
||||||
*/
|
*/
|
||||||
public ModuleVisitor visitModule(String name, int access, String version) {
|
public ModuleVisitor visitModule(String name, int access, String version) {
|
||||||
@@ -187,11 +187,11 @@ public abstract class ClassVisitor {
|
|||||||
* internal name of the enclosing class of the class.
|
* internal name of the enclosing class of the class.
|
||||||
* @param name
|
* @param name
|
||||||
* the name of the method that contains the class, or
|
* the name of the method that contains the class, or
|
||||||
* <tt>null</tt> if the class is not enclosed in a method of its
|
* <code>null</code> if the class is not enclosed in a method of its
|
||||||
* enclosing class.
|
* enclosing class.
|
||||||
* @param desc
|
* @param desc
|
||||||
* the descriptor of the method that contains the class, or
|
* the descriptor of the method that contains the class, or
|
||||||
* <tt>null</tt> if the class is not enclosed in a method of its
|
* <code>null</code> if the class is not enclosed in a method of its
|
||||||
* enclosing class.
|
* enclosing class.
|
||||||
*/
|
*/
|
||||||
public void visitOuterClass(String owner, String name, String desc) {
|
public void visitOuterClass(String owner, String name, String desc) {
|
||||||
@@ -206,8 +206,8 @@ public abstract class ClassVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||||
@@ -231,12 +231,12 @@ public abstract class ClassVisitor {
|
|||||||
* @param typePath
|
* @param typePath
|
||||||
* the path to the annotated type argument, wildcard bound, array
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
* element type, or static inner type within 'typeRef'. May be
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
* <code>null</code> if the annotation targets 'typeRef' as a whole.
|
||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||||
@@ -269,10 +269,10 @@ public abstract class ClassVisitor {
|
|||||||
* @param outerName
|
* @param outerName
|
||||||
* the internal name of the class to which the inner class
|
* the internal name of the class to which the inner class
|
||||||
* belongs (see {@link Type#getInternalName() getInternalName}).
|
* belongs (see {@link Type#getInternalName() getInternalName}).
|
||||||
* May be <tt>null</tt> for not member classes.
|
* May be <code>null</code> for not member classes.
|
||||||
* @param innerName
|
* @param innerName
|
||||||
* the (simple) name of the inner class inside its enclosing
|
* the (simple) name of the inner class inside its enclosing
|
||||||
* class. May be <tt>null</tt> for anonymous inner classes.
|
* class. May be <code>null</code> for anonymous inner classes.
|
||||||
* @param access
|
* @param access
|
||||||
* the access flags of the inner class as originally declared in
|
* the access flags of the inner class as originally declared in
|
||||||
* the enclosing class.
|
* the enclosing class.
|
||||||
@@ -295,20 +295,20 @@ public abstract class ClassVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the field's descriptor (see {@link Type Type}).
|
* the field's descriptor (see {@link Type Type}).
|
||||||
* @param signature
|
* @param signature
|
||||||
* the field's signature. May be <tt>null</tt> if the field's
|
* the field's signature. May be <code>null</code> if the field's
|
||||||
* type does not use generic types.
|
* type does not use generic types.
|
||||||
* @param value
|
* @param value
|
||||||
* the field's initial value. This parameter, which may be
|
* the field's initial value. This parameter, which may be
|
||||||
* <tt>null</tt> if the field does not have an initial value,
|
* <code>null</code> if the field does not have an initial value,
|
||||||
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
|
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
|
||||||
* {@link Double} or a {@link String} (for <tt>int</tt>,
|
* {@link Double} or a {@link String} (for <code>int</code>,
|
||||||
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
|
* <code>float</code>, <code>long</code> or <code>String</code> fields
|
||||||
* respectively). <i>This parameter is only used for static
|
* respectively). <i>This parameter is only used for static
|
||||||
* fields</i>. Its value is ignored for non static fields, which
|
* fields</i>. Its value is ignored for non static fields, which
|
||||||
* must be initialized through bytecode instructions in
|
* must be initialized through bytecode instructions in
|
||||||
* constructors or methods.
|
* constructors or methods.
|
||||||
* @return a visitor to visit field annotations and attributes, or
|
* @return a visitor to visit field annotations and attributes, or
|
||||||
* <tt>null</tt> if this class visitor is not interested in visiting
|
* <code>null</code> if this class visitor is not interested in visiting
|
||||||
* these annotations and attributes.
|
* these annotations and attributes.
|
||||||
*/
|
*/
|
||||||
public FieldVisitor visitField(int access, String name, String desc,
|
public FieldVisitor visitField(int access, String name, String desc,
|
||||||
@@ -321,7 +321,7 @@ public abstract class ClassVisitor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Visits a method of the class. This method <i>must</i> return a new
|
* 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 <code>null</code>) each time it is called,
|
||||||
* i.e., it should not return a previously returned visitor.
|
* i.e., it should not return a previously returned visitor.
|
||||||
*
|
*
|
||||||
* @param access
|
* @param access
|
||||||
@@ -333,14 +333,14 @@ public abstract class ClassVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the method's descriptor (see {@link Type Type}).
|
* the method's descriptor (see {@link Type Type}).
|
||||||
* @param signature
|
* @param signature
|
||||||
* the method's signature. May be <tt>null</tt> if the method
|
* the method's signature. May be <code>null</code> if the method
|
||||||
* parameters, return type and exceptions do not use generic
|
* parameters, return type and exceptions do not use generic
|
||||||
* types.
|
* types.
|
||||||
* @param exceptions
|
* @param exceptions
|
||||||
* the internal names of the method's exception classes (see
|
* the internal names of the method's exception classes (see
|
||||||
* {@link Type#getInternalName() getInternalName}). May be
|
* {@link Type#getInternalName() getInternalName}). May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
* @return an object to visit the byte code of the method, or <tt>null</tt>
|
* @return an object to visit the byte code of the method, or <code>null</code>
|
||||||
* if this class visitor is not interested in visiting the code of
|
* if this class visitor is not interested in visiting the code of
|
||||||
* this method.
|
* this method.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -391,8 +391,8 @@ public class ClassWriter extends ClassVisitor {
|
|||||||
* A type table used to temporarily store internal names that will not
|
* 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
|
* 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
|
* 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>
|
* map frames from scratch. This array associates to each index <code>i</code>
|
||||||
* the Item whose index is <tt>i</tt>. All Item objects stored in this array
|
* the Item whose index is <code>i</code>. All Item objects stored in this array
|
||||||
* are also stored in the {@link #items} hash table. These two arrays allow
|
* 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
|
* 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
|
* Item from its value. Each Item stores an internal name in its
|
||||||
@@ -556,7 +556,7 @@ public class ClassWriter extends ClassVisitor {
|
|||||||
private int compute;
|
private int compute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <tt>true</tt> if some methods have wide forward jumps using ASM pseudo
|
* <code>true</code> if some methods have wide forward jumps using ASM pseudo
|
||||||
* instructions, which need to be expanded into sequences of standard
|
* instructions, which need to be expanded into sequences of standard
|
||||||
* bytecode instructions. In this case the class is re-read and re-written
|
* bytecode instructions. In this case the class is re-read and re-written
|
||||||
* with a ClassReader -> ClassWriter chain to perform this transformation.
|
* with a ClassReader -> ClassWriter chain to perform this transformation.
|
||||||
@@ -1486,7 +1486,7 @@ public class ClassWriter extends ClassVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the method's descriptor.
|
* the method's descriptor.
|
||||||
* @param itf
|
* @param itf
|
||||||
* <tt>true</tt> if <tt>owner</tt> is an interface.
|
* <code>true</code> if <code>owner</code> is an interface.
|
||||||
* @return a new or already existing method reference item.
|
* @return a new or already existing method reference item.
|
||||||
*/
|
*/
|
||||||
Item newMethodItem(final String owner, final String name,
|
Item newMethodItem(final String owner, final String name,
|
||||||
@@ -1515,7 +1515,7 @@ public class ClassWriter extends ClassVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the method's descriptor.
|
* the method's descriptor.
|
||||||
* @param itf
|
* @param itf
|
||||||
* <tt>true</tt> if <tt>owner</tt> is an interface.
|
* <code>true</code> if <code>owner</code> is an interface.
|
||||||
* @return the index of a new or already existing method reference item.
|
* @return the index of a new or already existing method reference item.
|
||||||
*/
|
*/
|
||||||
public int newMethod(final String owner, final String name,
|
public int newMethod(final String owner, final String name,
|
||||||
@@ -1778,7 +1778,7 @@ public class ClassWriter extends ClassVisitor {
|
|||||||
* @param key
|
* @param key
|
||||||
* a constant pool item.
|
* a constant pool item.
|
||||||
* @return the constant pool's hash table item which is equal to the given
|
* @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 <code>null</code> if there is no such item.
|
||||||
*/
|
*/
|
||||||
private Item get(final Item key) {
|
private Item get(final Item key) {
|
||||||
Item i = items[key.hashCode % items.length];
|
Item i = items[key.hashCode % items.length];
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ package org.redkale.asm;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A visitor to visit a Java field. The methods of this class must be called in
|
* A visitor to visit a Java field. The methods of this class must be called in
|
||||||
* the following order: ( <tt>visitAnnotation</tt> |
|
* the following order: ( <code>visitAnnotation</code> |
|
||||||
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
|
* <code>visitTypeAnnotation</code> | <code>visitAttribute</code> )* <code>visitEnd</code>.
|
||||||
*
|
*
|
||||||
* @author Eric Bruneton
|
* @author Eric Bruneton
|
||||||
*/
|
*/
|
||||||
@@ -111,8 +111,8 @@ public abstract class FieldVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||||
@@ -132,12 +132,12 @@ public abstract class FieldVisitor {
|
|||||||
* @param typePath
|
* @param typePath
|
||||||
* the path to the annotated type argument, wildcard bound, array
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
* element type, or static inner type within 'typeRef'. May be
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
* <code>null</code> if the annotation targets 'typeRef' as a whole.
|
||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||||
|
|||||||
@@ -100,28 +100,28 @@ final class FieldWriter extends FieldVisitor {
|
|||||||
private int value;
|
private int value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime visible annotations of this field. May be <tt>null</tt>.
|
* The runtime visible annotations of this field. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter anns;
|
private AnnotationWriter anns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime invisible annotations of this field. May be <tt>null</tt>.
|
* The runtime invisible annotations of this field. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter ianns;
|
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 <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter tanns;
|
private AnnotationWriter tanns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime invisible type annotations of this field. May be
|
* The runtime invisible type annotations of this field. May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter itanns;
|
private AnnotationWriter itanns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The non standard attributes of this field. May be <tt>null</tt>.
|
* The non standard attributes of this field. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private Attribute attrs;
|
private Attribute attrs;
|
||||||
|
|
||||||
@@ -141,9 +141,9 @@ final class FieldWriter extends FieldVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the field's descriptor (see {@link Type}).
|
* the field's descriptor (see {@link Type}).
|
||||||
* @param signature
|
* @param signature
|
||||||
* the field's signature. May be <tt>null</tt>.
|
* the field's signature. May be <code>null</code>.
|
||||||
* @param value
|
* @param value
|
||||||
* the field's constant value. May be <tt>null</tt>.
|
* the field's constant value. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
FieldWriter(final ClassWriter cw, final int access, final String name,
|
FieldWriter(final ClassWriter cw, final int access, final String name,
|
||||||
final String desc, final String signature, final Object value) {
|
final String desc, final String signature, final Object value) {
|
||||||
|
|||||||
@@ -1403,7 +1403,7 @@ class Frame {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the input frame of the given basic block with the input and output
|
* 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 <code>true</code> if the input frame of
|
||||||
* the given label has been changed by this operation.
|
* the given label has been changed by this operation.
|
||||||
*
|
*
|
||||||
* @param cw
|
* @param cw
|
||||||
@@ -1413,7 +1413,7 @@ class Frame {
|
|||||||
* @param edge
|
* @param edge
|
||||||
* the kind of the {@link Edge} between this label and 'label'.
|
* the kind of the {@link Edge} between this label and 'label'.
|
||||||
* See {@link Edge#info}.
|
* See {@link Edge#info}.
|
||||||
* @return <tt>true</tt> if the input frame of the given label has been
|
* @return <code>true</code> if the input frame of the given label has been
|
||||||
* changed by this operation.
|
* changed by this operation.
|
||||||
*/
|
*/
|
||||||
final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
|
final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
|
||||||
@@ -1511,7 +1511,7 @@ class Frame {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the type at the given index in the given type array with the given
|
* 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 <code>true</code> if the type array has been modified by this
|
||||||
* operation.
|
* operation.
|
||||||
*
|
*
|
||||||
* @param cw
|
* @param cw
|
||||||
@@ -1522,7 +1522,7 @@ class Frame {
|
|||||||
* an array of types.
|
* an array of types.
|
||||||
* @param index
|
* @param index
|
||||||
* the index of the type that must be merged in 'types'.
|
* 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 <code>true</code> if the type array has been modified by this
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
private static boolean merge(final ClassWriter cw, int t,
|
private static boolean merge(final ClassWriter cw, int t,
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class Handler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal name of the type of exceptions handled by this handler, or
|
* Internal name of the type of exceptions handled by this handler, or
|
||||||
* <tt>null</tt> to catch any exceptions.
|
* <code>null</code> to catch any exceptions.
|
||||||
*/
|
*/
|
||||||
String desc;
|
String desc;
|
||||||
|
|
||||||
|
|||||||
@@ -306,8 +306,8 @@ final class Item {
|
|||||||
* @param i
|
* @param i
|
||||||
* the item to be compared to this one. Both items must have the
|
* the item to be compared to this one. Both items must have the
|
||||||
* same {@link #type}.
|
* same {@link #type}.
|
||||||
* @return <tt>true</tt> if the given item if equal to this one,
|
* @return <code>true</code> if the given item if equal to this one,
|
||||||
* <tt>false</tt> otherwise.
|
* <code>false</code> otherwise.
|
||||||
*/
|
*/
|
||||||
boolean isEqualTo(final Item i) {
|
boolean isEqualTo(final Item i) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|||||||
@@ -325,8 +325,8 @@ public class Label {
|
|||||||
* the position of first byte of the bytecode instruction that
|
* the position of first byte of the bytecode instruction that
|
||||||
* contains this label.
|
* contains this label.
|
||||||
* @param wideOffset
|
* @param wideOffset
|
||||||
* <tt>true</tt> if the reference must be stored in 4 bytes, or
|
* <code>true</code> if the reference must be stored in 4 bytes, or
|
||||||
* <tt>false</tt> if it must be stored with 2 bytes.
|
* <code>false</code> if it must be stored with 2 bytes.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* if this label has not been created by the given code writer.
|
* if this label has not been created by the given code writer.
|
||||||
*/
|
*/
|
||||||
@@ -389,7 +389,7 @@ public class Label {
|
|||||||
* the position of this label in the bytecode.
|
* the position of this label in the bytecode.
|
||||||
* @param data
|
* @param data
|
||||||
* the bytecode of the method.
|
* the bytecode of the method.
|
||||||
* @return <tt>true</tt> if a blank that was left for this label was too
|
* @return <code>true</code> if a blank that was left for this label was too
|
||||||
* small to store the offset. In such a case the corresponding jump
|
* small to store the offset. In such a case the corresponding jump
|
||||||
* instruction is replaced with a pseudo instruction (using unused
|
* instruction is replaced with a pseudo instruction (using unused
|
||||||
* opcodes) using an unsigned two bytes offset. These pseudo
|
* opcodes) using an unsigned two bytes offset. These pseudo
|
||||||
|
|||||||
@@ -60,24 +60,24 @@ package org.redkale.asm;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A visitor to visit a Java method. The methods of this class must be called in
|
* A visitor to visit a Java method. The methods of this class must be called in
|
||||||
* the following order: ( <tt>visitParameter</tt> )* [
|
* the following order: ( <code>visitParameter</code> )* [
|
||||||
* <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
|
* <code>visitAnnotationDefault</code> ] ( <code>visitAnnotation</code> |
|
||||||
* <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> |
|
* <code>visitParameterAnnotation</code> <code>visitTypeAnnotation</code> |
|
||||||
* <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
|
* <code>visitAttribute</code> )* [ <code>visitCode</code> ( <code>visitFrame</code> |
|
||||||
* <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> |
|
* <code>visit<i>X</i>Insn</code> | <code>visitLabel</code> |
|
||||||
* <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> |
|
* <code>visitInsnAnnotation</code> | <code>visitTryCatchBlock</code> |
|
||||||
* <tt>visitTryCatchAnnotation</tt> | <tt>visitLocalVariable</tt> |
|
* <code>visitTryCatchAnnotation</code> | <code>visitLocalVariable</code> |
|
||||||
* <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )*
|
* <code>visitLocalVariableAnnotation</code> | <code>visitLineNumber</code> )*
|
||||||
* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the
|
* <code>visitMaxs</code> ] <code>visitEnd</code>. In addition, the
|
||||||
* <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must be called in
|
* <code>visit<i>X</i>Insn</code> and <code>visitLabel</code> methods must be called in
|
||||||
* the sequential order of the bytecode instructions of the visited code,
|
* the sequential order of the bytecode instructions of the visited code,
|
||||||
* <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
|
* <code>visitInsnAnnotation</code> must be called <i>after</i> the annotated
|
||||||
* instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
|
* instruction, <code>visitTryCatchBlock</code> must be called <i>before</i> the
|
||||||
* labels passed as arguments have been visited,
|
* labels passed as arguments have been visited,
|
||||||
* <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
|
* <code>visitTryCatchBlockAnnotation</code> must be called <i>after</i> the
|
||||||
* corresponding try catch block has been visited, and the
|
* corresponding try catch block has been visited, and the
|
||||||
* <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
|
* <code>visitLocalVariable</code>, <code>visitLocalVariableAnnotation</code> and
|
||||||
* <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
|
* <code>visitLineNumber</code> methods must be called <i>after</i> the labels
|
||||||
* passed as arguments have been visited.
|
* passed as arguments have been visited.
|
||||||
*
|
*
|
||||||
* @author Eric Bruneton
|
* @author Eric Bruneton
|
||||||
@@ -132,8 +132,8 @@ public abstract class MethodVisitor {
|
|||||||
* @param name
|
* @param name
|
||||||
* parameter name or null if none is provided.
|
* parameter name or null if none is provided.
|
||||||
* @param access
|
* @param access
|
||||||
* the parameter's access flags, only <tt>ACC_FINAL</tt>,
|
* the parameter's access flags, only <code>ACC_FINAL</code>,
|
||||||
* <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
|
* <code>ACC_SYNTHETIC</code> or/and <code>ACC_MANDATED</code> are
|
||||||
* allowed (see {@link Opcodes}).
|
* allowed (see {@link Opcodes}).
|
||||||
*/
|
*/
|
||||||
public void visitParameter(String name, int access) {
|
public void visitParameter(String name, int access) {
|
||||||
@@ -146,7 +146,7 @@ public abstract class MethodVisitor {
|
|||||||
* Visits the default value of this annotation interface method.
|
* Visits the default value of this annotation interface method.
|
||||||
*
|
*
|
||||||
* @return a visitor to the visit the actual default value of this
|
* @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 <code>null</code> if this visitor is
|
||||||
* not interested in visiting this default value. The 'name'
|
* not interested in visiting this default value. The 'name'
|
||||||
* parameters passed to the methods of this annotation visitor are
|
* parameters passed to the methods of this annotation visitor are
|
||||||
* ignored. Moreover, exacly one visit method must be called on this
|
* ignored. Moreover, exacly one visit method must be called on this
|
||||||
@@ -165,8 +165,8 @@ public abstract class MethodVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||||
@@ -193,12 +193,12 @@ public abstract class MethodVisitor {
|
|||||||
* @param typePath
|
* @param typePath
|
||||||
* the path to the annotated type argument, wildcard bound, array
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
* element type, or static inner type within 'typeRef'. May be
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
* <code>null</code> if the annotation targets 'typeRef' as a whole.
|
||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||||
@@ -217,8 +217,8 @@ public abstract class MethodVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitParameterAnnotation(int parameter,
|
public AnnotationVisitor visitParameterAnnotation(int parameter,
|
||||||
@@ -569,7 +569,7 @@ public abstract class MethodVisitor {
|
|||||||
* the constant to be loaded on the stack. This parameter must be
|
* the constant to be loaded on the stack. This parameter must be
|
||||||
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
|
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
|
||||||
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
|
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
|
||||||
* ARRAY sort for <tt>.class</tt> constants, for classes whose
|
* ARRAY sort for <code>.class</code> constants, for classes whose
|
||||||
* version is 49.0, a {@link Type} of METHOD sort or a
|
* version is 49.0, a {@link Type} of METHOD sort or a
|
||||||
* {@link Handle} for MethodType and MethodHandle constants, for
|
* {@link Handle} for MethodType and MethodHandle constants, for
|
||||||
* classes whose version is 51.0.
|
* classes whose version is 51.0.
|
||||||
@@ -604,8 +604,8 @@ public abstract class MethodVisitor {
|
|||||||
* @param dflt
|
* @param dflt
|
||||||
* beginning of the default handler block.
|
* beginning of the default handler block.
|
||||||
* @param labels
|
* @param labels
|
||||||
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
|
* beginnings of the handler blocks. <code>labels[i]</code> is the
|
||||||
* beginning of the handler block for the <tt>min + i</tt> key.
|
* beginning of the handler block for the <code>min + i</code> key.
|
||||||
*/
|
*/
|
||||||
public void visitTableSwitchInsn(int min, int max, Label dflt,
|
public void visitTableSwitchInsn(int min, int max, Label dflt,
|
||||||
Label... labels) {
|
Label... labels) {
|
||||||
@@ -622,8 +622,8 @@ public abstract class MethodVisitor {
|
|||||||
* @param keys
|
* @param keys
|
||||||
* the values of the keys.
|
* the values of the keys.
|
||||||
* @param labels
|
* @param labels
|
||||||
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
|
* beginnings of the handler blocks. <code>labels[i]</code> is the
|
||||||
* beginning of the handler block for the <tt>keys[i]</tt> key.
|
* beginning of the handler block for the <code>keys[i]</code> key.
|
||||||
*/
|
*/
|
||||||
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
||||||
if (mv != null) {
|
if (mv != null) {
|
||||||
@@ -668,12 +668,12 @@ public abstract class MethodVisitor {
|
|||||||
* @param typePath
|
* @param typePath
|
||||||
* the path to the annotated type argument, wildcard bound, array
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
* element type, or static inner type within 'typeRef'. May be
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
* <code>null</code> if the annotation targets 'typeRef' as a whole.
|
||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitInsnAnnotation(int typeRef,
|
public AnnotationVisitor visitInsnAnnotation(int typeRef,
|
||||||
@@ -699,7 +699,7 @@ public abstract class MethodVisitor {
|
|||||||
* beginning of the exception handler's code.
|
* beginning of the exception handler's code.
|
||||||
* @param type
|
* @param type
|
||||||
* internal name of the type of exceptions handled by the
|
* internal name of the type of exceptions handled by the
|
||||||
* handler, or <tt>null</tt> to catch any exceptions (for
|
* handler, or <code>null</code> to catch any exceptions (for
|
||||||
* "finally" blocks).
|
* "finally" blocks).
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* if one of the labels has already been visited by this visitor
|
* if one of the labels has already been visited by this visitor
|
||||||
@@ -725,12 +725,12 @@ public abstract class MethodVisitor {
|
|||||||
* @param typePath
|
* @param typePath
|
||||||
* the path to the annotated type argument, wildcard bound, array
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
* element type, or static inner type within 'typeRef'. May be
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
* <code>null</code> if the annotation targets 'typeRef' as a whole.
|
||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
|
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
|
||||||
@@ -750,7 +750,7 @@ public abstract class MethodVisitor {
|
|||||||
* the type descriptor of this local variable.
|
* the type descriptor of this local variable.
|
||||||
* @param signature
|
* @param signature
|
||||||
* the type signature of this local variable. May be
|
* the type signature of this local variable. May be
|
||||||
* <tt>null</tt> if the local variable type does not use generic
|
* <code>null</code> if the local variable type does not use generic
|
||||||
* types.
|
* types.
|
||||||
* @param start
|
* @param start
|
||||||
* the first instruction corresponding to the scope of this local
|
* the first instruction corresponding to the scope of this local
|
||||||
@@ -782,7 +782,7 @@ public abstract class MethodVisitor {
|
|||||||
* @param typePath
|
* @param typePath
|
||||||
* the path to the annotated type argument, wildcard bound, array
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
* element type, or static inner type within 'typeRef'. May be
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
* <code>null</code> if the annotation targets 'typeRef' as a whole.
|
||||||
* @param start
|
* @param start
|
||||||
* the fist instructions corresponding to the continuous ranges
|
* the fist instructions corresponding to the continuous ranges
|
||||||
* that make the scope of this local variable (inclusive).
|
* that make the scope of this local variable (inclusive).
|
||||||
@@ -796,8 +796,8 @@ public abstract class MethodVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the class descriptor of the annotation class.
|
* the class descriptor of the annotation class.
|
||||||
* @param visible
|
* @param visible
|
||||||
* <tt>true</tt> if the annotation is visible at runtime.
|
* <code>true</code> if the annotation is visible at runtime.
|
||||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
* @return a visitor to visit the annotation values, or <code>null</code> if
|
||||||
* this visitor is not interested in visiting this annotation.
|
* this visitor is not interested in visiting this annotation.
|
||||||
*/
|
*/
|
||||||
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
||||||
@@ -819,7 +819,7 @@ public abstract class MethodVisitor {
|
|||||||
* @param start
|
* @param start
|
||||||
* the first instruction corresponding to this line number.
|
* the first instruction corresponding to this line number.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* if <tt>start</tt> has not already been visited by this
|
* if <code>start</code> has not already been visited by this
|
||||||
* visitor (by the {@link #visitLabel visitLabel} method).
|
* visitor (by the {@link #visitLabel visitLabel} method).
|
||||||
*/
|
*/
|
||||||
public void visitLineNumber(int line, Label start) {
|
public void visitLineNumber(int line, Label start) {
|
||||||
|
|||||||
@@ -218,41 +218,41 @@ class MethodWriter extends MethodVisitor {
|
|||||||
int[] exceptions;
|
int[] exceptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The annotation default attribute of this method. May be <tt>null</tt>.
|
* The annotation default attribute of this method. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private ByteVector annd;
|
private ByteVector annd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime visible annotations of this method. May be <tt>null</tt>.
|
* The runtime visible annotations of this method. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter anns;
|
private AnnotationWriter anns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime invisible annotations of this method. May be <tt>null</tt>.
|
* The runtime invisible annotations of this method. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter ianns;
|
private AnnotationWriter ianns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime visible type annotations of this method. May be <tt>null</tt>
|
* The runtime visible type annotations of this method. May be <code>null</code>
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter tanns;
|
private AnnotationWriter tanns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime invisible type annotations of this method. May be
|
* The runtime invisible type annotations of this method. May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter itanns;
|
private AnnotationWriter itanns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime visible parameter annotations of this method. May be
|
* The runtime visible parameter annotations of this method. May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter[] panns;
|
private AnnotationWriter[] panns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime invisible parameter annotations of this method. May be
|
* The runtime invisible parameter annotations of this method. May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter[] ipanns;
|
private AnnotationWriter[] ipanns;
|
||||||
|
|
||||||
@@ -381,12 +381,12 @@ class MethodWriter extends MethodVisitor {
|
|||||||
private int lastCodeOffset;
|
private int lastCodeOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime visible type annotations of the code. May be <tt>null</tt>.
|
* The runtime visible type annotations of the code. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter ctanns;
|
private AnnotationWriter ctanns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The runtime invisible type annotations of the code. May be <tt>null</tt>.
|
* The runtime invisible type annotations of the code. May be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
private AnnotationWriter ictanns;
|
private AnnotationWriter ictanns;
|
||||||
|
|
||||||
@@ -446,7 +446,7 @@ class MethodWriter extends MethodVisitor {
|
|||||||
* is relative to the beginning of the current basic block, i.e., the true
|
* is relative to the beginning of the current basic block, i.e., the true
|
||||||
* stack size after the last visited instruction is equal to the
|
* stack size after the last visited instruction is equal to the
|
||||||
* {@link Label#inputStackTop beginStackSize} of the current basic block
|
* {@link Label#inputStackTop beginStackSize} of the current basic block
|
||||||
* plus <tt>stackSize</tt>.
|
* plus <code>stackSize</code>.
|
||||||
*/
|
*/
|
||||||
private int stackSize;
|
private int stackSize;
|
||||||
|
|
||||||
@@ -455,7 +455,7 @@ class MethodWriter extends MethodVisitor {
|
|||||||
* This size is relative to the beginning of the current basic block, i.e.,
|
* This size is relative to the beginning of the current basic block, i.e.,
|
||||||
* the true maximum stack size after the last visited instruction is equal
|
* the true maximum stack size after the last visited instruction is equal
|
||||||
* to the {@link Label#inputStackTop beginStackSize} of the current basic
|
* to the {@link Label#inputStackTop beginStackSize} of the current basic
|
||||||
* block plus <tt>stackSize</tt>.
|
* block plus <code>stackSize</code>.
|
||||||
*/
|
*/
|
||||||
private int maxStackSize;
|
private int maxStackSize;
|
||||||
|
|
||||||
@@ -475,10 +475,10 @@ class MethodWriter extends MethodVisitor {
|
|||||||
* @param desc
|
* @param desc
|
||||||
* the method's descriptor (see {@link Type}).
|
* the method's descriptor (see {@link Type}).
|
||||||
* @param signature
|
* @param signature
|
||||||
* the method's signature. May be <tt>null</tt>.
|
* the method's signature. May be <code>null</code>.
|
||||||
* @param exceptions
|
* @param exceptions
|
||||||
* the internal names of the method's exceptions. May be
|
* the internal names of the method's exceptions. May be
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
* @param compute
|
* @param compute
|
||||||
* Indicates what must be automatically computed (see #compute).
|
* Indicates what must be automatically computed (see #compute).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ package org.redkale.asm;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A visitor to visit a Java module. The methods of this class must be called in
|
* A visitor to visit a Java module. The methods of this class must be called in
|
||||||
* the following order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> |
|
* the following order: <code>visitMainClass</code> | ( <code>visitPackage</code> |
|
||||||
* <tt>visitRequire</tt> | <tt>visitExport</tt> | <tt>visitOpen</tt> |
|
* <code>visitRequire</code> | <code>visitExport</code> | <code>visitOpen</code> |
|
||||||
* <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
|
* <code>visitUse</code> | <code>visitProvide</code> )* <code>visitEnd</code>.
|
||||||
*
|
*
|
||||||
* The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
|
* The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
|
||||||
* {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
|
* {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
|
||||||
@@ -157,7 +157,7 @@ public abstract class ModuleVisitor {
|
|||||||
* {@code ACC_MANDATED}.
|
* {@code ACC_MANDATED}.
|
||||||
* @param modules the qualified names of the modules that can access to
|
* @param modules the qualified names of the modules that can access to
|
||||||
* the public classes of the exported package or
|
* the public classes of the exported package or
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public void visitExport(String packaze, int access, String... modules) {
|
public void visitExport(String packaze, int access, String... modules) {
|
||||||
if (mv != null) {
|
if (mv != null) {
|
||||||
@@ -174,7 +174,7 @@ public abstract class ModuleVisitor {
|
|||||||
* {@code ACC_MANDATED}.
|
* {@code ACC_MANDATED}.
|
||||||
* @param modules the qualified names of the modules that can use deep
|
* @param modules the qualified names of the modules that can use deep
|
||||||
* reflection to the classes of the open package or
|
* reflection to the classes of the open package or
|
||||||
* <tt>null</tt>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public void visitOpen(String packaze, int access, String... modules) {
|
public void visitOpen(String packaze, int access, String... modules) {
|
||||||
if (mv != null) {
|
if (mv != null) {
|
||||||
|
|||||||
@@ -71,47 +71,47 @@ import java.lang.reflect.Method;
|
|||||||
public class Type {
|
public class Type {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>void</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int VOID = 0;
|
public static final int VOID = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>boolean</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int BOOLEAN = 1;
|
public static final int BOOLEAN = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>char</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int CHAR = 2;
|
public static final int CHAR = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>byte</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int BYTE = 3;
|
public static final int BYTE = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>short</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int SHORT = 4;
|
public static final int SHORT = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>int</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int INT = 5;
|
public static final int INT = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>float</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int FLOAT = 6;
|
public static final int FLOAT = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>long</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int LONG = 7;
|
public static final int LONG = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
|
* The sort of the <code>double</code> type. See {@link #getSort getSort}.
|
||||||
*/
|
*/
|
||||||
public static final int DOUBLE = 8;
|
public static final int DOUBLE = 8;
|
||||||
|
|
||||||
@@ -131,55 +131,55 @@ public class Type {
|
|||||||
public static final int METHOD = 11;
|
public static final int METHOD = 11;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>void</tt> type.
|
* The <code>void</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
|
public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
|
||||||
| (5 << 16) | (0 << 8) | 0, 1);
|
| (5 << 16) | (0 << 8) | 0, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>boolean</tt> type.
|
* The <code>boolean</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
|
public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
|
||||||
| (0 << 16) | (5 << 8) | 1, 1);
|
| (0 << 16) | (5 << 8) | 1, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>char</tt> type.
|
* The <code>char</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
|
public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
|
||||||
| (0 << 16) | (6 << 8) | 1, 1);
|
| (0 << 16) | (6 << 8) | 1, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>byte</tt> type.
|
* The <code>byte</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
|
public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
|
||||||
| (0 << 16) | (5 << 8) | 1, 1);
|
| (0 << 16) | (5 << 8) | 1, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>short</tt> type.
|
* The <code>short</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
|
public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
|
||||||
| (0 << 16) | (7 << 8) | 1, 1);
|
| (0 << 16) | (7 << 8) | 1, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>int</tt> type.
|
* The <code>int</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
|
public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
|
||||||
| (0 << 16) | (0 << 8) | 1, 1);
|
| (0 << 16) | (0 << 8) | 1, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>float</tt> type.
|
* The <code>float</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
|
public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
|
||||||
| (2 << 16) | (2 << 8) | 1, 1);
|
| (2 << 16) | (2 << 8) | 1, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>long</tt> type.
|
* The <code>long</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
|
public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
|
||||||
| (1 << 16) | (1 << 8) | 2, 1);
|
| (1 << 16) | (1 << 8) | 2, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <tt>double</tt> type.
|
* The <code>double</code> type.
|
||||||
*/
|
*/
|
||||||
public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
|
public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
|
||||||
| (3 << 16) | (3 << 8) | 2, 1);
|
| (3 << 16) | (3 << 8) | 2, 1);
|
||||||
@@ -439,8 +439,8 @@ public class Type {
|
|||||||
* @return the size of the arguments of the method (plus one for the
|
* @return the size of the arguments of the method (plus one for the
|
||||||
* implicit this argument), argSize, and the size of its return
|
* implicit this argument), argSize, and the size of its return
|
||||||
* value, retSize, packed into a single int i =
|
* value, retSize, packed into a single int i =
|
||||||
* <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to
|
* <code>(argSize << 2) | retSize</code> (argSize is therefore equal to
|
||||||
* <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
|
* <code>i >> 2</code>, and retSize to <code>i & 0x03</code>).
|
||||||
*/
|
*/
|
||||||
public static int getArgumentsAndReturnSizes(final String desc) {
|
public static int getArgumentsAndReturnSizes(final String desc) {
|
||||||
int n = 1;
|
int n = 1;
|
||||||
@@ -645,9 +645,9 @@ public class Type {
|
|||||||
* @return the size of the arguments (plus one for the implicit this
|
* @return the size of the arguments (plus one for the implicit this
|
||||||
* argument), argSize, and the size of the return value, retSize,
|
* argument), argSize, and the size of the return value, retSize,
|
||||||
* packed into a single
|
* packed into a single
|
||||||
* int i = <tt>(argSize << 2) | retSize</tt>
|
* int i = <code>(argSize << 2) | retSize</code>
|
||||||
* (argSize is therefore equal to <tt>i >> 2</tt>,
|
* (argSize is therefore equal to <code>i >> 2</code>,
|
||||||
* and retSize to <tt>i & 0x03</tt>).
|
* and retSize to <code>i & 0x03</code>).
|
||||||
*/
|
*/
|
||||||
public int getArgumentsAndReturnSizes() {
|
public int getArgumentsAndReturnSizes() {
|
||||||
return getArgumentsAndReturnSizes(getDescriptor());
|
return getArgumentsAndReturnSizes(getDescriptor());
|
||||||
@@ -838,8 +838,8 @@ public class Type {
|
|||||||
* Returns the size of values of this type. This method must not be used for
|
* Returns the size of values of this type. This method must not be used for
|
||||||
* method types.
|
* method types.
|
||||||
*
|
*
|
||||||
* @return the size of values of this type, i.e., 2 for <tt>long</tt> and
|
* @return the size of values of this type, i.e., 2 for <code>long</code> and
|
||||||
* <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
|
* <code>double</code>, 0 for <code>void</code> and 1 otherwise.
|
||||||
*/
|
*/
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
// the size is in byte 0 of 'off' for primitive types (buf == null)
|
// the size is in byte 0 of 'off' for primitive types (buf == null)
|
||||||
@@ -855,8 +855,8 @@ public class Type {
|
|||||||
* ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
|
* ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
|
||||||
* ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
|
* ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
|
||||||
* @return an opcode that is similar to the given opcode, but adapted to
|
* @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
|
* this Java type. For example, if this type is <code>float</code> and
|
||||||
* <tt>opcode</tt> is IRETURN, this method returns FRETURN.
|
* <code>opcode</code> is IRETURN, this method returns FRETURN.
|
||||||
*/
|
*/
|
||||||
public int getOpcode(final int opcode) {
|
public int getOpcode(final int opcode) {
|
||||||
if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
|
if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
|
||||||
@@ -879,7 +879,7 @@ public class Type {
|
|||||||
*
|
*
|
||||||
* @param o
|
* @param o
|
||||||
* the object to be compared to this type.
|
* the object to be compared to this type.
|
||||||
* @return <tt>true</tt> if the given object is equal to this type.
|
* @return <code>true</code> if the given object is equal to this type.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object o) {
|
public boolean equals(final Object o) {
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ public final class ApiDocsService {
|
|||||||
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
|
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
|
||||||
out.write(json.getBytes("UTF-8"));
|
out.write(json.getBytes("UTF-8"));
|
||||||
out.close();
|
out.close();
|
||||||
File doctemplate = new File(app.getConfPath(), "apidoc-template.html");
|
File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html");
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
if (doctemplate.isFile() && doctemplate.canRead()) {
|
if (doctemplate.isFile() && doctemplate.canRead()) {
|
||||||
in = new FileInputStream(doctemplate);
|
in = new FileInputStream(doctemplate);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import org.redkale.cluster.ClusterAgent;
|
||||||
import org.redkale.util.RedkaleClassLoader;
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
import org.redkale.net.TransportGroupInfo;
|
import org.redkale.net.TransportGroupInfo;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -23,7 +24,8 @@ import javax.xml.parsers.*;
|
|||||||
import org.redkale.boot.ClassFilter.FilterEntry;
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
import org.redkale.convert.Convert;
|
import org.redkale.convert.Convert;
|
||||||
import org.redkale.convert.bson.BsonFactory;
|
import org.redkale.convert.bson.BsonFactory;
|
||||||
import org.redkale.convert.json.JsonFactory;
|
import org.redkale.convert.json.*;
|
||||||
|
import org.redkale.mq.*;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.http.MimeType;
|
import org.redkale.net.http.MimeType;
|
||||||
import org.redkale.net.sncp.*;
|
import org.redkale.net.sncp.*;
|
||||||
@@ -57,12 +59,17 @@ public final class Application {
|
|||||||
public static final String RESNAME_APP_TIME = "APP_TIME";
|
public static final String RESNAME_APP_TIME = "APP_TIME";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前进程的根目录, 类型:String、File、Path
|
* 当前进程的名称, 类型:String
|
||||||
|
*/
|
||||||
|
public static final String RESNAME_APP_NAME = "APP_NAME";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前进程的根目录, 类型:String、File、Path、URI
|
||||||
*/
|
*/
|
||||||
public static final String RESNAME_APP_HOME = "APP_HOME";
|
public static final String RESNAME_APP_HOME = "APP_HOME";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前进程的配置目录,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、File、Path
|
* 当前进程的配置目录,如果不是绝对路径则视为HOME目录下的相对路径 类型:String、File、Path、URI
|
||||||
*/
|
*/
|
||||||
public static final String RESNAME_APP_CONF = "APP_CONF";
|
public static final String RESNAME_APP_CONF = "APP_CONF";
|
||||||
|
|
||||||
@@ -72,12 +79,12 @@ public final class Application {
|
|||||||
public static final String RESNAME_APP_GRES = "APP_GRES";
|
public static final String RESNAME_APP_GRES = "APP_GRES";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前进程节点的name, 类型:String
|
* 当前进程节点的nodeid, 类型:int
|
||||||
*/
|
*/
|
||||||
public static final String RESNAME_APP_NODE = "APP_NODE";
|
public static final String RESNAME_APP_NODEID = "APP_NODEID";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前进程节点的IP地址, 类型:InetAddress、String
|
* 当前进程节点的IP地址, 类型:InetSocketAddress、InetAddress、String
|
||||||
*/
|
*/
|
||||||
public static final String RESNAME_APP_ADDR = "APP_ADDR";
|
public static final String RESNAME_APP_ADDR = "APP_ADDR";
|
||||||
|
|
||||||
@@ -106,8 +113,14 @@ public final class Application {
|
|||||||
*/
|
*/
|
||||||
public static final String RESNAME_SERVER_RESFACTORY = Server.RESNAME_SERVER_RESFACTORY;
|
public static final String RESNAME_SERVER_RESFACTORY = Server.RESNAME_SERVER_RESFACTORY;
|
||||||
|
|
||||||
|
//本进程节点ID
|
||||||
|
final int nodeid;
|
||||||
|
|
||||||
|
//本进程节点ID
|
||||||
|
final String name;
|
||||||
|
|
||||||
//本地IP地址
|
//本地IP地址
|
||||||
final InetAddress localAddress;
|
final InetSocketAddress localAddress;
|
||||||
|
|
||||||
//CacheSource 资源
|
//CacheSource 资源
|
||||||
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
|
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
|
||||||
@@ -115,18 +128,29 @@ public final class Application {
|
|||||||
//DataSource 资源
|
//DataSource 资源
|
||||||
final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
|
final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
//NodeServer 资源
|
//NodeServer 资源, 顺序必须是sncps, others, watchs
|
||||||
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
|
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
//SNCP传输端的TransportFactory, 注意: 只给SNCP使用
|
//SNCP传输端的TransportFactory, 注意: 只给SNCP使用
|
||||||
final TransportFactory sncpTransportFactory;
|
final TransportFactory sncpTransportFactory;
|
||||||
|
|
||||||
|
//第三方服务发现管理接口
|
||||||
|
//@since 2.1.0
|
||||||
|
final ClusterAgent clusterAgent;
|
||||||
|
|
||||||
|
//MQ管理接口
|
||||||
|
//@since 2.1.0
|
||||||
|
final MessageAgent[] messageAgents;
|
||||||
|
|
||||||
//全局根ResourceFactory
|
//全局根ResourceFactory
|
||||||
final ResourceFactory resourceFactory = ResourceFactory.root();
|
final ResourceFactory resourceFactory = ResourceFactory.root();
|
||||||
|
|
||||||
//服务配置项
|
//服务配置项
|
||||||
final AnyValue config;
|
final AnyValue config;
|
||||||
|
|
||||||
|
//排除的jar路径
|
||||||
|
final String excludelibs;
|
||||||
|
|
||||||
//临时计数器
|
//临时计数器
|
||||||
CountDownLatch servicecdl; //会出现两次赋值
|
CountDownLatch servicecdl; //会出现两次赋值
|
||||||
|
|
||||||
@@ -135,7 +159,7 @@ public final class Application {
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------
|
||||||
//是否用于main方法运行
|
//是否用于main方法运行
|
||||||
private final boolean singletonrun;
|
final boolean singletonrun;
|
||||||
|
|
||||||
//根WatchFactory
|
//根WatchFactory
|
||||||
//private final WatchFactory watchFactory = WatchFactory.root();
|
//private final WatchFactory watchFactory = WatchFactory.root();
|
||||||
@@ -143,7 +167,7 @@ public final class Application {
|
|||||||
private final File home;
|
private final File home;
|
||||||
|
|
||||||
//配置文件目录
|
//配置文件目录
|
||||||
private final File confPath;
|
private final URI confPath;
|
||||||
|
|
||||||
//日志
|
//日志
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
@@ -176,44 +200,46 @@ public final class Application {
|
|||||||
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
|
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
|
||||||
this.resourceFactory.register(RESNAME_APP_HOME, Path.class, root.toPath());
|
this.resourceFactory.register(RESNAME_APP_HOME, Path.class, root.toPath());
|
||||||
this.resourceFactory.register(RESNAME_APP_HOME, File.class, root);
|
this.resourceFactory.register(RESNAME_APP_HOME, File.class, root);
|
||||||
|
this.resourceFactory.register(RESNAME_APP_HOME, URI.class, root.toURI());
|
||||||
try {
|
try {
|
||||||
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
|
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
|
||||||
this.home = root.getCanonicalFile();
|
this.home = root.getCanonicalFile();
|
||||||
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
||||||
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
if (confsubpath.contains("://")) {
|
||||||
this.confPath = new File(confsubpath).getCanonicalFile();
|
this.confPath = new URI(confsubpath);
|
||||||
|
} else if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||||
|
this.confPath = new File(confsubpath).getCanonicalFile().toURI();
|
||||||
} else {
|
} else {
|
||||||
this.confPath = new File(this.home, confsubpath).getCanonicalFile();
|
this.confPath = new File(this.home, confsubpath).getCanonicalFile().toURI();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
String localaddr = config.getValue("address", "").trim();
|
String localaddr = config.getValue("address", "").trim();
|
||||||
this.localAddress = localaddr.isEmpty() ? Utility.localInetAddress() : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
|
InetAddress addr = localaddr.isEmpty() ? Utility.localInetAddress() : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
|
||||||
this.resourceFactory.register(RESNAME_APP_ADDR, this.localAddress.getHostAddress());
|
this.localAddress = new InetSocketAddress(addr, config.getIntValue("port"));
|
||||||
this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, this.localAddress);
|
this.resourceFactory.register(RESNAME_APP_ADDR, addr.getHostAddress());
|
||||||
|
this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, addr);
|
||||||
|
this.resourceFactory.register(RESNAME_APP_ADDR, InetSocketAddress.class, this.localAddress);
|
||||||
|
|
||||||
{
|
{
|
||||||
String node = config.getValue("node", "").trim();
|
int nid = config.getIntValue("nodeid", 0);
|
||||||
if (node.isEmpty()) {
|
this.nodeid = nid;
|
||||||
StringBuilder sb = new StringBuilder();
|
this.resourceFactory.register(RESNAME_APP_NODEID, nid);
|
||||||
byte[] bs = this.localAddress.getAddress();
|
System.setProperty(RESNAME_APP_NODEID, "" + nid);
|
||||||
int v1 = bs[bs.length - 2] & 0xff;
|
}
|
||||||
int v2 = bs[bs.length - 1] & 0xff;
|
{
|
||||||
if (v1 <= 0xf) sb.append('0');
|
this.name = checkName(config.getValue("name", ""));
|
||||||
sb.append(Integer.toHexString(v1));
|
this.resourceFactory.register(RESNAME_APP_NAME, name);
|
||||||
if (v2 <= 0xf) sb.append('0');
|
System.setProperty(RESNAME_APP_NAME, name);
|
||||||
sb.append(Integer.toHexString(v2));
|
|
||||||
node = sb.toString();
|
|
||||||
}
|
|
||||||
this.resourceFactory.register(RESNAME_APP_NODE, node);
|
|
||||||
System.setProperty(RESNAME_APP_NODE, node);
|
|
||||||
}
|
}
|
||||||
//以下是初始化日志配置
|
//以下是初始化日志配置
|
||||||
final File logconf = new File(confPath, "logging.properties");
|
final URI logConfURI = "file".equals(confPath.getScheme()) ? new File(new File(confPath), "logging.properties").toURI()
|
||||||
if (logconf.isFile() && logconf.canRead()) {
|
: URI.create(confPath.toString() + (confPath.toString().endsWith("/") ? "" : "/") + "logging.properties");
|
||||||
|
if (!"file".equals(confPath.getScheme()) || (new File(logConfURI).isFile() && new File(logConfURI).canRead())) {
|
||||||
try {
|
try {
|
||||||
final String rootpath = root.getCanonicalPath().replace('\\', '/');
|
final String rootpath = root.getCanonicalPath().replace('\\', '/');
|
||||||
FileInputStream fin = new FileInputStream(logconf);
|
InputStream fin = logConfURI.toURL().openStream();
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.load(fin);
|
properties.load(fin);
|
||||||
fin.close();
|
fin.close();
|
||||||
@@ -267,6 +293,9 @@ public final class Application {
|
|||||||
AsynchronousChannelGroup transportGroup = null;
|
AsynchronousChannelGroup transportGroup = null;
|
||||||
final AnyValue resources = config.getAnyValue("resources");
|
final AnyValue resources = config.getAnyValue("resources");
|
||||||
TransportStrategy strategy = null;
|
TransportStrategy strategy = null;
|
||||||
|
String excludelib0 = null;
|
||||||
|
ClusterAgent cluster = null;
|
||||||
|
MessageAgent[] mqs = null;
|
||||||
int bufferCapacity = 32 * 1024;
|
int bufferCapacity = 32 * 1024;
|
||||||
int bufferPoolSize = Runtime.getRuntime().availableProcessors() * 8;
|
int bufferPoolSize = Runtime.getRuntime().availableProcessors() * 8;
|
||||||
int readTimeoutSeconds = TransportFactory.DEFAULT_READTIMEOUTSECONDS;
|
int readTimeoutSeconds = TransportFactory.DEFAULT_READTIMEOUTSECONDS;
|
||||||
@@ -274,6 +303,8 @@ public final class Application {
|
|||||||
AtomicLong createBufferCounter = new AtomicLong();
|
AtomicLong createBufferCounter = new AtomicLong();
|
||||||
AtomicLong cycleBufferCounter = new AtomicLong();
|
AtomicLong cycleBufferCounter = new AtomicLong();
|
||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
|
AnyValue excludelibConf = resources.getAnyValue("excludelibs");
|
||||||
|
if (excludelibConf != null) excludelib0 = excludelibConf.getValue("value");
|
||||||
AnyValue transportConf = resources.getAnyValue("transport");
|
AnyValue transportConf = resources.getAnyValue("transport");
|
||||||
int groupsize = resources.getAnyValues("group").length;
|
int groupsize = resources.getAnyValues("group").length;
|
||||||
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
|
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
|
||||||
@@ -301,7 +332,7 @@ public final class Application {
|
|||||||
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
|
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
|
||||||
@@ -310,13 +341,87 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity / 1024 + "K; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
|
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity / 1024 + "K; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnyValue clusterConf = resources.getAnyValue("cluster");
|
||||||
|
if (clusterConf != null) {
|
||||||
|
try {
|
||||||
|
String classval = clusterConf.getValue("value");
|
||||||
|
if (classval == null || classval.isEmpty()) {
|
||||||
|
Iterator<ClusterAgent> it = ServiceLoader.load(ClusterAgent.class, classLoader).iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
ClusterAgent agent = it.next();
|
||||||
|
if (agent.match(clusterConf)) {
|
||||||
|
cluster = agent;
|
||||||
|
cluster.setConfig(clusterConf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cluster == null) logger.log(Level.SEVERE, "load application cluster resource, but not found name='value' value error: " + clusterConf);
|
||||||
|
} else {
|
||||||
|
Class type = classLoader.loadClass(clusterConf.getValue("value"));
|
||||||
|
if (!ClusterAgent.class.isAssignableFrom(type)) {
|
||||||
|
logger.log(Level.SEVERE, "load application cluster resource, but not found " + ClusterAgent.class.getSimpleName() + " implements class error: " + clusterConf);
|
||||||
|
} else {
|
||||||
|
cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance();
|
||||||
|
cluster.setConfig(clusterConf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnyValue[] mqConfs = resources.getAnyValues("mq");
|
||||||
|
if (mqConfs != null && mqConfs.length > 0) {
|
||||||
|
mqs = new MessageAgent[mqConfs.length];
|
||||||
|
Set<String> mqnames = new HashSet<>();
|
||||||
|
for (int i = 0; i < mqConfs.length; i++) {
|
||||||
|
AnyValue mqConf = mqConfs[0];
|
||||||
|
String mqname = mqConf.getValue("name", "");
|
||||||
|
if (mqnames.contains(mqname)) throw new RuntimeException("mq.name(" + mqname + ") is repeat");
|
||||||
|
mqnames.add(mqname);
|
||||||
|
String namex = mqConf.getValue("names");
|
||||||
|
if (namex != null && !namex.isEmpty()) {
|
||||||
|
for (String n : namex.split(";")) {
|
||||||
|
if (n.trim().isEmpty()) continue;
|
||||||
|
if (mqnames.contains(n.trim())) throw new RuntimeException("mq.name(" + n.trim() + ") is repeat");
|
||||||
|
mqnames.add(n.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String classval = mqConf.getValue("value");
|
||||||
|
if (classval == null || classval.isEmpty()) {
|
||||||
|
Iterator<MessageAgent> it = ServiceLoader.load(MessageAgent.class, classLoader).iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
MessageAgent messageAgent = it.next();
|
||||||
|
if (messageAgent.match(mqConf)) {
|
||||||
|
mqs[i] = messageAgent;
|
||||||
|
mqs[i].setConfig(mqConf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mqs[i] == null) logger.log(Level.SEVERE, "load application mq resource, but not found name='value' value error: " + mqConf);
|
||||||
|
} else {
|
||||||
|
Class type = classLoader.loadClass(classval);
|
||||||
|
if (!MessageAgent.class.isAssignableFrom(type)) {
|
||||||
|
logger.log(Level.SEVERE, "load application mq resource, but not found " + MessageAgent.class.getSimpleName() + " implements class error: " + mqConf);
|
||||||
|
} else {
|
||||||
|
mqs[i] = (MessageAgent) type.getDeclaredConstructor().newInstance();
|
||||||
|
mqs[i].setConfig(mqConf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "load application mq resource error: " + mqs[i], e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (transportGroup == null) {
|
if (transportGroup == null) {
|
||||||
final AtomicInteger counter = new AtomicInteger();
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
|
transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.setDaemon(true);
|
t.setDaemon(true);
|
||||||
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
t.setName("Redkale-Transport-Thread-" + counter.incrementAndGet());
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
@@ -334,15 +439,29 @@ public final class Application {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.excludelibs = excludelib0;
|
||||||
this.sncpTransportFactory = TransportFactory.create(transportExec, transportPool, transportGroup, (SSLContext) null, readTimeoutSeconds, writeTimeoutSeconds, strategy);
|
this.sncpTransportFactory = TransportFactory.create(transportExec, transportPool, transportGroup, (SSLContext) null, readTimeoutSeconds, writeTimeoutSeconds, strategy);
|
||||||
DefaultAnyValue tarnsportConf = DefaultAnyValue.create(TransportFactory.NAME_POOLMAXCONNS, System.getProperty("net.transport.poolmaxconns", "100"))
|
DefaultAnyValue tarnsportConf = DefaultAnyValue.create(TransportFactory.NAME_POOLMAXCONNS, System.getProperty("net.transport.pool.maxconns", "100"))
|
||||||
.addValue(TransportFactory.NAME_PINGINTERVAL, System.getProperty("net.transport.pinginterval", "30"))
|
.addValue(TransportFactory.NAME_PINGINTERVAL, System.getProperty("net.transport.ping.interval", "30"))
|
||||||
.addValue(TransportFactory.NAME_CHECKINTERVAL, System.getProperty("net.transport.checkinterval", "30"));
|
.addValue(TransportFactory.NAME_CHECKINTERVAL, System.getProperty("net.transport.check.interval", "30"));
|
||||||
this.sncpTransportFactory.init(tarnsportConf, Sncp.PING_BUFFER, Sncp.PONG_BUFFER.remaining());
|
this.sncpTransportFactory.init(tarnsportConf, Sncp.PING_BUFFER, Sncp.PONG_BUFFER.remaining());
|
||||||
|
this.clusterAgent = cluster;
|
||||||
|
this.messageAgents = mqs;
|
||||||
Thread.currentThread().setContextClassLoader(this.classLoader);
|
Thread.currentThread().setContextClassLoader(this.classLoader);
|
||||||
this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
|
this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String checkName(String name) { //不能含特殊字符
|
||||||
|
if (name.isEmpty()) return name;
|
||||||
|
if (name.charAt(0) >= '0' && name.charAt(0) <= '9') throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9");
|
||||||
|
for (char ch : name.toCharArray()) {
|
||||||
|
if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //不能含特殊字符
|
||||||
|
throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
public ResourceFactory getResourceFactory() {
|
public ResourceFactory getResourceFactory() {
|
||||||
return resourceFactory;
|
return resourceFactory;
|
||||||
}
|
}
|
||||||
@@ -351,6 +470,22 @@ public final class Application {
|
|||||||
return sncpTransportFactory;
|
return sncpTransportFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClusterAgent getClusterAgent() {
|
||||||
|
return clusterAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAgent getMessageAgent(String name) {
|
||||||
|
if (messageAgents == null) return null;
|
||||||
|
for (MessageAgent agent : messageAgents) {
|
||||||
|
if (agent.getName().equals(name)) return agent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAgent[] getMessageAgents() {
|
||||||
|
return messageAgents;
|
||||||
|
}
|
||||||
|
|
||||||
public RedkaleClassLoader getClassLoader() {
|
public RedkaleClassLoader getClassLoader() {
|
||||||
return classLoader;
|
return classLoader;
|
||||||
}
|
}
|
||||||
@@ -371,11 +506,19 @@ public final class Application {
|
|||||||
return new ArrayList<>(cacheSources);
|
return new ArrayList<>(cacheSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getNodeid() {
|
||||||
|
return nodeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
public File getHome() {
|
public File getHome() {
|
||||||
return home;
|
return home;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getConfPath() {
|
public URI getConfPath() {
|
||||||
return confPath;
|
return confPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,10 +541,14 @@ public final class Application {
|
|||||||
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
|
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
|
||||||
System.setProperty("convert.json.writer.buffer.defsize", "4096");
|
System.setProperty("convert.json.writer.buffer.defsize", "4096");
|
||||||
|
|
||||||
File persist = new File(this.confPath, "persistence.xml");
|
final String confpath = this.confPath.toString();
|
||||||
final String homepath = this.home.getCanonicalPath();
|
final String homepath = this.home.getCanonicalPath();
|
||||||
final String confpath = this.confPath.getCanonicalPath();
|
if ("file".equals(this.confPath.getScheme())) {
|
||||||
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
File persist = new File(new File(confPath), "persistence.xml");
|
||||||
|
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
||||||
|
} else {
|
||||||
|
System.setProperty(DataSources.DATASOURCE_CONFPATH, confpath + (confpath.endsWith("/") ? "" : "/") + "persistence.xml");
|
||||||
|
}
|
||||||
String pidstr = "";
|
String pidstr = "";
|
||||||
try { //JDK 9+
|
try { //JDK 9+
|
||||||
Class phclass = Class.forName("java.lang.ProcessHandle");
|
Class phclass = Class.forName("java.lang.ProcessHandle");
|
||||||
@@ -410,7 +557,7 @@ public final class Application {
|
|||||||
pidstr = "APP_PID = " + pid + "\r\n";
|
pidstr = "APP_PID = " + pid + "\r\n";
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
}
|
}
|
||||||
logger.log(Level.INFO, pidstr + "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath + "\r\n" + RESNAME_APP_CONF + " = " + confpath);
|
logger.log(Level.INFO, pidstr + "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" + this.localAddress.getPort() + "\r\n" + RESNAME_APP_HOME + " = " + homepath + "\r\n" + RESNAME_APP_CONF + " = " + confpath);
|
||||||
String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath);
|
String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath);
|
||||||
lib = lib.isEmpty() ? confpath : (lib + ";" + confpath);
|
lib = lib.isEmpty() ? confpath : (lib + ";" + confpath);
|
||||||
Server.loadLib(classLoader, logger, lib);
|
Server.loadLib(classLoader, logger, lib);
|
||||||
@@ -425,13 +572,17 @@ public final class Application {
|
|||||||
if (dfloads != null) {
|
if (dfloads != null) {
|
||||||
for (String dfload : dfloads.split(";")) {
|
for (String dfload : dfloads.split(";")) {
|
||||||
if (dfload.trim().isEmpty()) continue;
|
if (dfload.trim().isEmpty()) continue;
|
||||||
final File df = (dfload.indexOf('/') < 0) ? new File(confPath, "/" + dfload) : new File(dfload);
|
final URI df = (dfload.indexOf('/') < 0) ? URI.create(confpath + (confpath.endsWith("/") ? "" : "/") + dfload) : new File(dfload).toURI();
|
||||||
if (df.isFile()) {
|
if (!"file".equals(df.getScheme()) || new File(df).isFile()) {
|
||||||
Properties ps = new Properties();
|
Properties ps = new Properties();
|
||||||
InputStream in = new FileInputStream(df);
|
try {
|
||||||
ps.load(in);
|
InputStream in = df.toURL().openStream();
|
||||||
in.close();
|
ps.load(in);
|
||||||
ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath)));
|
in.close();
|
||||||
|
ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "load properties(" + dfload + ") error", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -522,6 +673,41 @@ public final class Application {
|
|||||||
|
|
||||||
}, Application.class, ResourceFactory.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
|
}, Application.class, ResourceFactory.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
if (this.clusterAgent != null) {
|
||||||
|
if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "ClusterAgent initing");
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
clusterAgent.setTransportFactory(this.sncpTransportFactory);
|
||||||
|
this.resourceFactory.inject(clusterAgent);
|
||||||
|
clusterAgent.init(clusterAgent.getConfig());
|
||||||
|
this.resourceFactory.register(ClusterAgent.class, clusterAgent);
|
||||||
|
logger.info("ClusterAgent init in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
}
|
||||||
|
if (this.messageAgents != null) {
|
||||||
|
if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent initing");
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
for (MessageAgent agent : this.messageAgents) {
|
||||||
|
this.resourceFactory.inject(agent);
|
||||||
|
agent.init(agent.getConfig());
|
||||||
|
this.resourceFactory.register(agent.getName(), MessageAgent.class, agent);
|
||||||
|
this.resourceFactory.register(agent.getName(), HttpMessageClient.class, agent.getHttpMessageClient());
|
||||||
|
//this.resourceFactory.register(agent.getName(), SncpMessageClient.class, agent.getSncpMessageClient()); //不需要给开发者使用
|
||||||
|
}
|
||||||
|
logger.info("MessageAgent init in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
|
||||||
|
}
|
||||||
|
//------------------------------------- 注册 DataSource --------------------------------------------------------
|
||||||
|
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
|
||||||
|
try {
|
||||||
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if (clusterAgent == null) return;
|
||||||
|
HttpMessageClient messageClient = new HttpMessageClusterClient(clusterAgent);
|
||||||
|
field.set(src, messageClient);
|
||||||
|
rf.inject(messageClient, null); // 给其可能包含@Resource的字段赋值;
|
||||||
|
rf.register(resourceName, HttpMessageClient.class, messageClient);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject error", e);
|
||||||
|
}
|
||||||
|
}, HttpMessageClient.class);
|
||||||
initResources();
|
initResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +722,7 @@ public final class Application {
|
|||||||
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
|
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
|
||||||
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
|
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
|
||||||
}
|
}
|
||||||
TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, conf.getValue("subprotocol", ""), new LinkedHashSet<>());
|
TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, new LinkedHashSet<>());
|
||||||
for (AnyValue node : conf.getAnyValues("node")) {
|
for (AnyValue node : conf.getAnyValues("node")) {
|
||||||
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
|
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
|
||||||
ginfo.putAddress(addr);
|
ginfo.putAddress(addr);
|
||||||
@@ -558,9 +744,10 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void restoreConfig() throws IOException {
|
public void restoreConfig() throws IOException {
|
||||||
|
if (!"file".equals(this.confPath.getScheme())) return;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
File confFile = new File(this.confPath, "application.xml");
|
File confFile = new File(this.confPath.toString(), "application.xml");
|
||||||
confFile.renameTo(new File(this.confPath, "application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
|
confFile.renameTo(new File(this.confPath.toString(), "application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
|
||||||
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
|
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
|
||||||
ps.append(config.toXML("application"));
|
ps.append(config.toXML("application"));
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -571,7 +758,7 @@ public final class Application {
|
|||||||
final Application application = this;
|
final Application application = this;
|
||||||
new Thread() {
|
new Thread() {
|
||||||
{
|
{
|
||||||
setName("Application-Control-Thread");
|
setName("Redkale-Application-SelfServer-Thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -589,7 +776,8 @@ public final class Application {
|
|||||||
buffer.flip();
|
buffer.flip();
|
||||||
byte[] bytes = new byte[buffer.remaining()];
|
byte[] bytes = new byte[buffer.remaining()];
|
||||||
buffer.get(bytes);
|
buffer.get(bytes);
|
||||||
if ("SHUTDOWN".equalsIgnoreCase(new String(bytes))) {
|
final String cmd = new String(bytes);
|
||||||
|
if ("SHUTDOWN".equalsIgnoreCase(cmd)) {
|
||||||
try {
|
try {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
logger.info(application.getClass().getSimpleName() + " shutdowning");
|
logger.info(application.getClass().getSimpleName() + " shutdowning");
|
||||||
@@ -609,7 +797,7 @@ public final class Application {
|
|||||||
buffer.flip();
|
buffer.flip();
|
||||||
channel.send(buffer, address);
|
channel.send(buffer, address);
|
||||||
}
|
}
|
||||||
} else if ("APIDOC".equalsIgnoreCase(new String(bytes))) {
|
} else if ("APIDOC".equalsIgnoreCase(cmd)) {
|
||||||
try {
|
try {
|
||||||
new ApiDocsService(application).run();
|
new ApiDocsService(application).run();
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
@@ -622,6 +810,16 @@ public final class Application {
|
|||||||
buffer.flip();
|
buffer.flip();
|
||||||
channel.send(buffer, address);
|
channel.send(buffer, address);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
logger.info(application.getClass().getSimpleName() + " command " + cmd);
|
||||||
|
application.command(cmd);
|
||||||
|
buffer.clear();
|
||||||
|
buffer.put("COMMAND OK".getBytes());
|
||||||
|
buffer.flip();
|
||||||
|
channel.send(buffer, address);
|
||||||
|
long e = System.currentTimeMillis() - s;
|
||||||
|
logger.info(application.getClass().getSimpleName() + " command in " + e + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -632,10 +830,10 @@ public final class Application {
|
|||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendCommand(String command) throws Exception {
|
private static void sendCommand(Logger logger, int port, String command) throws Exception {
|
||||||
final DatagramChannel channel = DatagramChannel.open();
|
final DatagramChannel channel = DatagramChannel.open();
|
||||||
channel.configureBlocking(true);
|
channel.configureBlocking(true);
|
||||||
channel.connect(new InetSocketAddress("127.0.0.1", config.getIntValue("port")));
|
channel.connect(new InetSocketAddress("127.0.0.1", port));
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(128);
|
ByteBuffer buffer = ByteBuffer.allocate(128);
|
||||||
buffer.put(command.getBytes());
|
buffer.put(command.getBytes());
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
@@ -648,7 +846,7 @@ public final class Application {
|
|||||||
byte[] bytes = new byte[buffer.remaining()];
|
byte[] bytes = new byte[buffer.remaining()];
|
||||||
buffer.get(bytes);
|
buffer.get(bytes);
|
||||||
channel.close();
|
channel.close();
|
||||||
logger.info("Send: " + command + ", Reply: " + new String(bytes));
|
if (logger != null) logger.info("Send: " + command + ", Reply: " + new String(bytes));
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof PortUnreachableException) {
|
if (e instanceof PortUnreachableException) {
|
||||||
@@ -657,7 +855,7 @@ public final class Application {
|
|||||||
application.init();
|
application.init();
|
||||||
application.start();
|
application.start();
|
||||||
new ApiDocsService(application).run();
|
new ApiDocsService(application).run();
|
||||||
logger.info("APIDOC OK");
|
if (logger != null) logger.info("APIDOC OK");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -666,6 +864,9 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void start() throws Exception {
|
public void start() throws Exception {
|
||||||
|
if (!singletonrun && this.clusterAgent != null) {
|
||||||
|
this.clusterAgent.register(this);
|
||||||
|
}
|
||||||
final AnyValue[] entrys = config.getAnyValues("server");
|
final AnyValue[] entrys = config.getAnyValues("server");
|
||||||
CountDownLatch timecd = new CountDownLatch(entrys.length);
|
CountDownLatch timecd = new CountDownLatch(entrys.length);
|
||||||
final List<AnyValue> sncps = new ArrayList<>();
|
final List<AnyValue> sncps = new ArrayList<>();
|
||||||
@@ -687,12 +888,40 @@ public final class Application {
|
|||||||
runServers(timecd, others);
|
runServers(timecd, others);
|
||||||
runServers(timecd, watchs); //必须在所有服务都启动后再启动WATCH服务
|
runServers(timecd, watchs); //必须在所有服务都启动后再启动WATCH服务
|
||||||
timecd.await();
|
timecd.await();
|
||||||
|
if (this.clusterAgent != null) this.clusterAgent.start();
|
||||||
|
if (this.messageAgents != null) {
|
||||||
|
if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent starting");
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
final StringBuffer sb = new StringBuffer();
|
||||||
|
Set<String> names = new HashSet<>();
|
||||||
|
for (MessageAgent agent : this.messageAgents) {
|
||||||
|
names.add(agent.getName());
|
||||||
|
Map<String, Long> map = agent.start().join();
|
||||||
|
AtomicInteger maxlen = new AtomicInteger();
|
||||||
|
map.keySet().forEach(str -> {
|
||||||
|
if (str.length() > maxlen.get()) maxlen.set(str.length());
|
||||||
|
});
|
||||||
|
new TreeMap<>(map).forEach((topic, ms) -> sb.append("MessageConsumer(topic=").append(alignString(topic, maxlen.get())).append(") init and start in ").append(ms).append(" ms\r\n")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (sb.length() > 0) logger.info(sb.toString().trim());
|
||||||
|
logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") start in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
}
|
||||||
//if (!singletonrun) signalHandle();
|
//if (!singletonrun) signalHandle();
|
||||||
//if (!singletonrun) clearPersistData();
|
//if (!singletonrun) clearPersistData();
|
||||||
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n");
|
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n");
|
||||||
if (!singletonrun) this.serversLatch.await();
|
if (!singletonrun) this.serversLatch.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String alignString(String value, int maxlen) {
|
||||||
|
StringBuilder sb = new StringBuilder(maxlen);
|
||||||
|
sb.append(value);
|
||||||
|
for (int i = 0; i < maxlen - value.length(); i++) {
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
// private void clearPersistData() {
|
// private void clearPersistData() {
|
||||||
// File cachedir = new File(home, "cache");
|
// File cachedir = new File(home, "cache");
|
||||||
// if (!cachedir.isDirectory()) return;
|
// if (!cachedir.isDirectory()) return;
|
||||||
@@ -742,7 +971,7 @@ public final class Application {
|
|||||||
Thread thread = new Thread() {
|
Thread thread = new Thread() {
|
||||||
{
|
{
|
||||||
String host = serconf.getValue("host", "0.0.0.0").replace("0.0.0.0", "*");
|
String host = serconf.getValue("host", "0.0.0.0").replace("0.0.0.0", "*");
|
||||||
setName(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
|
setName("Redkale-" + serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
|
||||||
this.setDaemon(true);
|
this.setDaemon(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,20 +1000,18 @@ public final class Application {
|
|||||||
synchronized (nodeClasses) {
|
synchronized (nodeClasses) {
|
||||||
if (!inited.getAndSet(true)) { //加载自定义的协议,如:SOCKS
|
if (!inited.getAndSet(true)) { //加载自定义的协议,如:SOCKS
|
||||||
ClassFilter profilter = new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class, (Class[]) null);
|
ClassFilter profilter = new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class, (Class[]) null);
|
||||||
ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter);
|
ClassFilter.Loader.load(home, ((excludelibs != null ? (excludelibs + ";") : "") + serconf.getValue("excludelibs", "")).split(";"), profilter);
|
||||||
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
|
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
|
||||||
for (FilterEntry<NodeServer> entry : entrys) {
|
for (FilterEntry<NodeServer> entry : entrys) {
|
||||||
final Class<? extends NodeServer> type = entry.getType();
|
final Class<? extends NodeServer> type = entry.getType();
|
||||||
NodeProtocol pros = type.getAnnotation(NodeProtocol.class);
|
NodeProtocol pros = type.getAnnotation(NodeProtocol.class);
|
||||||
for (String p : pros.value()) {
|
String p = pros.value().toUpperCase();
|
||||||
p = p.toUpperCase();
|
if ("SNCP".equals(p) || "HTTP".equals(p)) continue;
|
||||||
if ("SNCP".equals(p) || "HTTP".equals(p)) continue;
|
final Class<? extends NodeServer> old = nodeClasses.get(p);
|
||||||
final Class<? extends NodeServer> old = nodeClasses.get(p);
|
if (old != null && old != type) {
|
||||||
if (old != null && old != type) {
|
throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
|
||||||
throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
|
|
||||||
}
|
|
||||||
nodeClasses.put(p, type);
|
|
||||||
}
|
}
|
||||||
|
nodeClasses.put(p, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -812,13 +1039,22 @@ public final class Application {
|
|||||||
sercdl.await();
|
sercdl.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Service> T singleton(Class<T> serviceClass) throws Exception {
|
public static <T extends Service> T singleton(Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
|
||||||
return singleton("", serviceClass);
|
return singleton("", serviceClass, extServiceClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Service> T singleton(String name, Class<T> serviceClass) throws Exception {
|
public static <T extends Service> T singleton(String name, Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
|
||||||
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
|
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
|
||||||
final Application application = Application.create(true);
|
final Application application = Application.create(true);
|
||||||
|
System.setProperty("red" + "kale.singleton.serviceclass", serviceClass.getName());
|
||||||
|
if (extServiceClasses != null && extServiceClasses.length > 0) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Class clazz : extServiceClasses) {
|
||||||
|
if (sb.length() > 0) sb.append(',');
|
||||||
|
sb.append(clazz.getName());
|
||||||
|
}
|
||||||
|
System.setProperty("red" + "kale.singleton.extserviceclasses", sb.toString());
|
||||||
|
}
|
||||||
application.init();
|
application.init();
|
||||||
application.start();
|
application.start();
|
||||||
for (NodeServer server : application.servers) {
|
for (NodeServer server : application.servers) {
|
||||||
@@ -831,30 +1067,34 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Application create(final boolean singleton) throws IOException {
|
public static Application create(final boolean singleton) throws IOException {
|
||||||
|
return new Application(singleton, loadAppXml());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AnyValue loadAppXml() throws IOException {
|
||||||
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
|
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
|
||||||
System.setProperty(RESNAME_APP_HOME, home);
|
System.setProperty(RESNAME_APP_HOME, home);
|
||||||
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
|
||||||
File appfile;
|
URI appconf;
|
||||||
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
if (confsubpath.contains("://")) {
|
||||||
appfile = new File(confsubpath).getCanonicalFile();
|
appconf = URI.create(confsubpath + (confsubpath.endsWith("/") ? "" : "/") + "application.xml");
|
||||||
|
} else if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
|
||||||
|
appconf = new File(confsubpath, "application.xml").toURI();
|
||||||
} else {
|
} else {
|
||||||
appfile = new File(new File(home), confsubpath);
|
appconf = new File(new File(home, confsubpath), "application.xml").toURI();
|
||||||
}
|
}
|
||||||
File appconf = new File(appfile, "application.xml");
|
return load(appconf.toURL().openStream());
|
||||||
return new Application(singleton, load(new FileInputStream(appconf)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Utility.midnight(); //先初始化一下Utility
|
Utility.midnight(); //先初始化一下Utility
|
||||||
|
Thread.currentThread().setName("Redkale-Application-Main-Thread");
|
||||||
//运行主程序
|
//运行主程序
|
||||||
final Application application = Application.create(false);
|
|
||||||
if (System.getProperty("CMD") != null) {
|
if (System.getProperty("CMD") != null) {
|
||||||
application.sendCommand(System.getProperty("CMD"));
|
AnyValue config = loadAppXml();
|
||||||
return;
|
Application.sendCommand(null, config.getIntValue("port"), System.getProperty("CMD"));
|
||||||
} else if (System.getProperty("SHUTDOWN") != null) { //兼容旧接口
|
|
||||||
application.sendCommand("SHUTDOWN");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final Application application = Application.create(false);
|
||||||
application.init();
|
application.init();
|
||||||
application.startSelfServer();
|
application.startSelfServer();
|
||||||
try {
|
try {
|
||||||
@@ -878,7 +1118,18 @@ public final class Application {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdown() throws Exception {
|
public void command(String cmd) {
|
||||||
|
List<NodeServer> localServers = new ArrayList<>(servers); //顺序sncps, others, watchs
|
||||||
|
localServers.stream().forEach((server) -> {
|
||||||
|
try {
|
||||||
|
server.command(cmd);
|
||||||
|
} catch (Exception t) {
|
||||||
|
logger.log(Level.WARNING, " command server(" + server.getSocketAddress() + ") error", t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() throws Exception {
|
||||||
for (ApplicationListener listener : this.listeners) {
|
for (ApplicationListener listener : this.listeners) {
|
||||||
try {
|
try {
|
||||||
listener.preShutdown(this);
|
listener.preShutdown(this);
|
||||||
@@ -886,8 +1137,26 @@ public final class Application {
|
|||||||
logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e);
|
logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
List<NodeServer> localServers = new ArrayList<>(servers); //顺序sncps, others, watchs
|
||||||
servers.stream().forEach((server) -> {
|
Collections.reverse(localServers); //倒序, 必须让watchs先关闭,watch包含服务发现和注销逻辑
|
||||||
|
if (this.messageAgents != null) {
|
||||||
|
Set<String> names = new HashSet<>();
|
||||||
|
if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent stopping");
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
for (MessageAgent agent : this.messageAgents) {
|
||||||
|
names.add(agent.getName());
|
||||||
|
agent.stop().join();
|
||||||
|
}
|
||||||
|
logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") stop in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
}
|
||||||
|
if (clusterAgent != null) {
|
||||||
|
if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "ClusterAgent destroying");
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
clusterAgent.deregister(this);
|
||||||
|
clusterAgent.destroy(clusterAgent.getConfig());
|
||||||
|
logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
}
|
||||||
|
localServers.stream().forEach((server) -> {
|
||||||
try {
|
try {
|
||||||
server.shutdown();
|
server.shutdown();
|
||||||
} catch (Exception t) {
|
} catch (Exception t) {
|
||||||
@@ -896,7 +1165,16 @@ public final class Application {
|
|||||||
serversLatch.countDown();
|
serversLatch.countDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (this.messageAgents != null) {
|
||||||
|
Set<String> names = new HashSet<>();
|
||||||
|
if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent destroying");
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
for (MessageAgent agent : this.messageAgents) {
|
||||||
|
names.add(agent.getName());
|
||||||
|
agent.destroy(agent.getConfig());
|
||||||
|
}
|
||||||
|
logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") destroy in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
}
|
||||||
for (DataSource source : dataSources) {
|
for (DataSource source : dataSources) {
|
||||||
if (source == null) continue;
|
if (source == null) continue;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.lang.reflect.Modifier;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.jar.*;
|
import java.util.jar.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import java.util.regex.*;
|
import java.util.regex.*;
|
||||||
@@ -36,6 +37,8 @@ public final class ClassFilter<T> {
|
|||||||
|
|
||||||
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
||||||
|
|
||||||
|
private Predicate<String> expectPredicate;
|
||||||
|
|
||||||
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
||||||
|
|
||||||
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
||||||
@@ -172,8 +175,9 @@ public final class ClassFilter<T> {
|
|||||||
}
|
}
|
||||||
if (!r && ors != null) {
|
if (!r && ors != null) {
|
||||||
for (ClassFilter filter : ors) {
|
for (ClassFilter filter : ors) {
|
||||||
if (filter.accept(property, clazzname)) {
|
if (filter.accept(filter.conf, clazzname)) {
|
||||||
cf = filter;
|
cf = filter;
|
||||||
|
property = cf.conf;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,17 +190,17 @@ public final class ClassFilter<T> {
|
|||||||
if (property == null) {
|
if (property == null) {
|
||||||
property = cf.conf;
|
property = cf.conf;
|
||||||
} else if (property instanceof DefaultAnyValue) {
|
} else if (property instanceof DefaultAnyValue) {
|
||||||
((DefaultAnyValue) property).addAll(cf.conf);
|
((DefaultAnyValue) property).addAllStringSet(cf.conf);
|
||||||
} else {
|
} else {
|
||||||
DefaultAnyValue dav = new DefaultAnyValue();
|
DefaultAnyValue dav = new DefaultAnyValue();
|
||||||
dav.addAll(property);
|
dav.addAllStringSet(property);
|
||||||
dav.addAll(cf.conf);
|
dav.addAllStringSet(cf.conf);
|
||||||
property = dav;
|
property = dav;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
||||||
if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)的
|
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)的
|
||||||
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
||||||
} else {
|
} else {
|
||||||
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
||||||
@@ -204,7 +208,9 @@ public final class ClassFilter<T> {
|
|||||||
} catch (Throwable cfe) {
|
} catch (Throwable cfe) {
|
||||||
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
||||||
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
|
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
|
||||||
&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) {
|
&& !clazzname.startsWith("com.mysql.") && !clazzname.startsWith("com.microsoft.")
|
||||||
|
&& !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);
|
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,7 +244,7 @@ public final class ClassFilter<T> {
|
|||||||
}
|
}
|
||||||
if (!r && ors != null) {
|
if (!r && ors != null) {
|
||||||
for (ClassFilter filter : ors) {
|
for (ClassFilter filter : ors) {
|
||||||
if (filter.accept(property, classname)) return true;
|
if (filter.accept(filter.conf, classname)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
@@ -347,6 +353,14 @@ public final class ClassFilter<T> {
|
|||||||
this.refused = refused;
|
this.refused = refused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Predicate<String> getExpectPredicate() {
|
||||||
|
return expectPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectPredicate(Predicate<String> predicate) {
|
||||||
|
this.expectPredicate = predicate;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getPrivilegeIncludes() {
|
public Set<String> getPrivilegeIncludes() {
|
||||||
return privilegeIncludes;
|
return privilegeIncludes;
|
||||||
}
|
}
|
||||||
@@ -394,7 +408,7 @@ public final class ClassFilter<T> {
|
|||||||
str = str.trim();
|
str = str.trim();
|
||||||
if (str.endsWith(";")) str = str.substring(0, str.length() - 1);
|
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.property = property;
|
||||||
this.autoload = autoload;
|
this.autoload = autoload;
|
||||||
this.expect = expect;
|
this.expect = expect;
|
||||||
@@ -404,7 +418,7 @@ public final class ClassFilter<T> {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName()
|
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
|
@Override
|
||||||
@@ -431,6 +445,10 @@ public final class ClassFilter<T> {
|
|||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean containsGroup(String group) {
|
||||||
|
return groups != null && groups.contains(group);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEmptyGroups() {
|
public boolean isEmptyGroups() {
|
||||||
return groups == null || groups.isEmpty();
|
return groups == null || groups.isEmpty();
|
||||||
}
|
}
|
||||||
@@ -482,7 +500,7 @@ public final class ClassFilter<T> {
|
|||||||
boolean skip = false;
|
boolean skip = false;
|
||||||
for (Pattern p : excludePatterns) {
|
for (Pattern p : excludePatterns) {
|
||||||
if (p.matcher(url.toString()).matches()) {
|
if (p.matcher(url.toString()).matches()) {
|
||||||
skip = false;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,19 +46,19 @@ public class LogFileHandler extends Handler {
|
|||||||
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";
|
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
|
@Override
|
||||||
public String format(LogRecord record) {
|
public String format(LogRecord log) {
|
||||||
String source;
|
String source;
|
||||||
if (record.getSourceClassName() != null) {
|
if (log.getSourceClassName() != null) {
|
||||||
source = record.getSourceClassName();
|
source = log.getSourceClassName();
|
||||||
if (record.getSourceMethodName() != null) {
|
if (log.getSourceMethodName() != null) {
|
||||||
source += " " + record.getSourceMethodName();
|
source += " " + log.getSourceMethodName();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
source = record.getLoggerName();
|
source = log.getLoggerName();
|
||||||
}
|
}
|
||||||
String message = formatMessage(record);
|
String message = formatMessage(log);
|
||||||
String throwable = "";
|
String throwable = "";
|
||||||
if (record.getThrown() != null) {
|
if (log.getThrown() != null) {
|
||||||
StringWriter sw = new StringWriter();
|
StringWriter sw = new StringWriter();
|
||||||
PrintWriter pw = new PrintWriter(sw) {
|
PrintWriter pw = new PrintWriter(sw) {
|
||||||
@Override
|
@Override
|
||||||
@@ -67,22 +67,22 @@ public class LogFileHandler extends Handler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
pw.println();
|
pw.println();
|
||||||
record.getThrown().printStackTrace(pw);
|
log.getThrown().printStackTrace(pw);
|
||||||
pw.close();
|
pw.close();
|
||||||
throwable = sw.toString();
|
throwable = sw.toString();
|
||||||
}
|
}
|
||||||
return String.format(format,
|
return String.format(format,
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
source,
|
source,
|
||||||
record.getLoggerName(),
|
log.getLoggerName(),
|
||||||
record.getLevel().getName(),
|
log.getLevel().getName(),
|
||||||
message,
|
message,
|
||||||
throwable);
|
throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final LinkedBlockingQueue<LogRecord> records = new LinkedBlockingQueue();
|
protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue();
|
||||||
|
|
||||||
private String pattern;
|
private String pattern;
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ public class LogFileHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void open() {
|
private void open() {
|
||||||
final String name = "Logging-" + getClass().getSimpleName() + "-Thread";
|
final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread";
|
||||||
new Thread() {
|
new Thread() {
|
||||||
{
|
{
|
||||||
setName(name);
|
setName(name);
|
||||||
@@ -144,9 +144,9 @@ public class LogFileHandler extends Handler {
|
|||||||
public void run() {
|
public void run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
LogRecord record = records.take();
|
LogRecord log = logqueue.take();
|
||||||
final boolean bigger = (limit > 0 && limit <= loglength.get());
|
final boolean bigger = (limit > 0 && limit <= loglength.get());
|
||||||
final boolean changeday = tomorrow <= record.getMillis();
|
final boolean changeday = tomorrow <= log.getMillis();
|
||||||
if (bigger || changeday) {
|
if (bigger || changeday) {
|
||||||
updateTomorrow();
|
updateTomorrow();
|
||||||
if (logstream != null) {
|
if (logstream != null) {
|
||||||
@@ -193,12 +193,12 @@ public class LogFileHandler extends Handler {
|
|||||||
logunusualstream = new FileOutputStream(logunusualfile, append);
|
logunusualstream = new FileOutputStream(logunusualfile, append);
|
||||||
}
|
}
|
||||||
//----------------------写日志-------------------------
|
//----------------------写日志-------------------------
|
||||||
String message = getFormatter().format(record);
|
String message = getFormatter().format(log);
|
||||||
String encoding = getEncoding();
|
String encoding = getEncoding();
|
||||||
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
|
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
|
||||||
logstream.write(bytes);
|
logstream.write(bytes);
|
||||||
loglength.addAndGet(bytes.length);
|
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);
|
logunusualstream.write(bytes);
|
||||||
logunusuallength.addAndGet(bytes.length);
|
logunusuallength.addAndGet(bytes.length);
|
||||||
}
|
}
|
||||||
@@ -310,21 +310,21 @@ public class LogFileHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void publish(LogRecord record) {
|
public void publish(LogRecord log) {
|
||||||
final String sourceClassName = record.getSourceClassName();
|
final String sourceClassName = log.getSourceClassName();
|
||||||
if (sourceClassName == null || true) {
|
if (sourceClassName == null || true) {
|
||||||
StackTraceElement[] ses = new Throwable().getStackTrace();
|
StackTraceElement[] ses = new Throwable().getStackTrace();
|
||||||
for (int i = 2; i < ses.length; i++) {
|
for (int i = 2; i < ses.length; i++) {
|
||||||
if (ses[i].getClassName().startsWith("java.util.logging")) continue;
|
if (ses[i].getClassName().startsWith("java.util.logging")) continue;
|
||||||
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
|
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
|
||||||
record.setSourceMethodName(ses[i].getMethodName());
|
log.setSourceMethodName(ses[i].getMethodName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
|
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
|
||||||
}
|
}
|
||||||
if (denyreg != null && denyreg.matcher(record.getMessage()).find()) return;
|
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
|
||||||
records.offer(record);
|
logqueue.offer(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import java.util.logging.Level;
|
|||||||
import javax.annotation.*;
|
import javax.annotation.*;
|
||||||
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
|
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
|
||||||
import org.redkale.boot.ClassFilter.FilterEntry;
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.cluster.ClusterAgent;
|
||||||
|
import org.redkale.mq.MessageAgent;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.http.*;
|
import org.redkale.net.http.*;
|
||||||
import org.redkale.net.sncp.Sncp;
|
import org.redkale.net.sncp.Sncp;
|
||||||
@@ -30,7 +32,7 @@ import org.redkale.watch.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@NodeProtocol({"HTTP"})
|
@NodeProtocol("HTTP")
|
||||||
public class NodeHttpServer extends NodeServer {
|
public class NodeHttpServer extends NodeServer {
|
||||||
|
|
||||||
protected final boolean rest; //是否加载REST服务, 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
|
protected final boolean rest; //是否加载REST服务, 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
|
||||||
@@ -120,7 +122,15 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
|
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
|
||||||
}
|
}
|
||||||
if (nodeService == null) {
|
if (nodeService == null) {
|
||||||
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
|
MessageAgent messageAgent = null;
|
||||||
|
try {
|
||||||
|
Field c = src.getClass().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, WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
|
||||||
regFactory.register(resourceName, WebSocketNode.class, nodeService);
|
regFactory.register(resourceName, WebSocketNode.class, nodeService);
|
||||||
}
|
}
|
||||||
resourceFactory.inject(nodeService, self);
|
resourceFactory.inject(nodeService, self);
|
||||||
@@ -136,7 +146,7 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
|
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
|
||||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||||
for (FilterEntry<? extends Filter> en : list) {
|
for (FilterEntry<? extends Filter> en : list) {
|
||||||
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
|
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
|
||||||
@@ -145,7 +155,7 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
resourceFactory.inject(filter, this);
|
resourceFactory.inject(filter, this);
|
||||||
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
||||||
this.httpServer.addHttpFilter(filter, filterConf);
|
this.httpServer.addHttpFilter(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());
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
}
|
}
|
||||||
@@ -158,7 +168,7 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
||||||
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
||||||
final String prefix = prefix0;
|
final String prefix = prefix0;
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys());
|
List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys());
|
||||||
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
|
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
|
||||||
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
|
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
|
||||||
@@ -176,7 +186,11 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
|
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
|
||||||
if (Modifier.isAbstract(clazz.getModifiers())) continue;
|
if (Modifier.isAbstract(clazz.getModifiers())) continue;
|
||||||
WebServlet ws = clazz.getAnnotation(WebServlet.class);
|
WebServlet ws = clazz.getAnnotation(WebServlet.class);
|
||||||
if (ws == null || ws.value().length == 0) continue;
|
if (ws == null) continue;
|
||||||
|
if (ws.value().length == 0) {
|
||||||
|
logger.log(Level.INFO, "not found @WebServlet.value in " + clazz.getName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance();
|
final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance();
|
||||||
resourceFactory.inject(servlet, this);
|
resourceFactory.inject(servlet, this);
|
||||||
final String[] mappings = ws.value();
|
final String[] mappings = ws.value();
|
||||||
@@ -192,12 +206,12 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
int max = 0;
|
int max = 0;
|
||||||
if (ss != null && sb != null) {
|
if (ss != null && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
if (as.getKey().length() > max) max = as.getKey().length();
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
}
|
}
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
sb.append(threadName).append(" Load ").append(as.getKey());
|
sb.append(localThreadName).append(" Load ").append(as.getKey());
|
||||||
for (int i = 0; i < max - as.getKey().length(); i++) {
|
for (int i = 0; i < max - as.getKey().length(); i++) {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
}
|
}
|
||||||
@@ -222,11 +236,18 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
String prefix0 = restConf.getValue("path", "");
|
String prefix0 = restConf.getValue("path", "");
|
||||||
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
||||||
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
||||||
final String prefix = prefix0;
|
|
||||||
|
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
||||||
|
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);
|
final boolean autoload = restConf.getBoolValue("autoload", true);
|
||||||
{ //加载RestService
|
{ //加载RestService
|
||||||
String userTypeStr = restConf.getValue("usertype");
|
String userTypeStr = restConf.getValue("usertype");
|
||||||
@@ -269,7 +290,9 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
if (ws != null && !ws.repair()) prefix2 = "";
|
if (ws != null && !ws.repair()) prefix2 = "";
|
||||||
resourceFactory.inject(servlet, NodeHttpServer.this);
|
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||||
//if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
|
dynServletMap.put(service, servlet);
|
||||||
|
if (messageAgent != null) messageAgent.putService(this, service, servlet);
|
||||||
|
//if (finest) logger.finest(localThreadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
|
||||||
if (ss != null) {
|
if (ss != null) {
|
||||||
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||||
for (int i = 0; i < mappings.length; i++) {
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
@@ -322,13 +345,13 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
restedObjects.add(stype); //避免重复创建Rest对象
|
restedObjects.add(stype); //避免重复创建Rest对象
|
||||||
HttpServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, prefix, en.getProperty());
|
WebSocketServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, messageAgent, prefix, en.getProperty());
|
||||||
if (servlet == null) return; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
|
if (servlet == null) return; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
|
||||||
String prefix2 = prefix;
|
String prefix2 = prefix;
|
||||||
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
if (ws != null && !ws.repair()) prefix2 = "";
|
if (ws != null && !ws.repair()) prefix2 = "";
|
||||||
resourceFactory.inject(servlet, NodeHttpServer.this);
|
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||||
if (finest) logger.finest(threadName + " " + stype.getName() + " create a RestWebSocketServlet");
|
if (finest) logger.finest(localThreadName + " " + stype.getName() + " create a RestWebSocketServlet");
|
||||||
if (ss != null) {
|
if (ss != null) {
|
||||||
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||||
for (int i = 0; i < mappings.length; i++) {
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
@@ -338,21 +361,39 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (messageAgent != null) this.messageAgents.put(messageAgent.getName(), messageAgent);
|
||||||
//输出信息
|
//输出信息
|
||||||
if (ss != null && !ss.isEmpty() && sb != null) {
|
if (ss != null && !ss.isEmpty() && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
int max = 0;
|
int max = 0;
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
if (as.getKey().length() > max) max = as.getKey().length();
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
}
|
}
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
sb.append(threadName).append(" Load ").append(as.getKey());
|
sb.append(localThreadName).append(" Load ").append(as.getKey());
|
||||||
for (int i = 0; i < max - as.getKey().length(); i++) {
|
for (int i = 0; i < max - as.getKey().length(); i++) {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
}
|
}
|
||||||
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
sb.append(threadName).append(" All HttpServlets load cost " + (System.currentTimeMillis() - starts) + " ms" + LINE_SEPARATOR);
|
sb.append(localThreadName).append(" All HttpServlets load cost ").append(System.currentTimeMillis() - starts).append(" ms").append(LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override //loadServlet执行之后调用
|
||||||
|
protected void postLoadServlets() {
|
||||||
|
final ClusterAgent cluster = application.clusterAgent;
|
||||||
|
if (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<>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,5 +20,5 @@ import java.lang.annotation.*;
|
|||||||
@Documented
|
@Documented
|
||||||
public @interface NodeProtocol {
|
public @interface NodeProtocol {
|
||||||
|
|
||||||
String[] value();
|
String value();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import org.redkale.cluster.ClusterAgent;
|
||||||
|
import org.redkale.mq.MessageAgent;
|
||||||
import org.redkale.util.RedkaleClassLoader;
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
@@ -27,7 +29,6 @@ import org.redkale.net.sncp.*;
|
|||||||
import org.redkale.service.*;
|
import org.redkale.service.*;
|
||||||
import org.redkale.source.*;
|
import org.redkale.source.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
import org.redkale.util.AnyValue.DefaultAnyValue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server节点的初始化配置类
|
* Server节点的初始化配置类
|
||||||
@@ -67,11 +68,13 @@ public abstract class NodeServer {
|
|||||||
private InetSocketAddress sncpAddress;
|
private InetSocketAddress sncpAddress;
|
||||||
|
|
||||||
//加载Service时的处理函数
|
//加载Service时的处理函数
|
||||||
protected Consumer<Service> consumer;
|
protected BiConsumer<MessageAgent, Service> consumer;
|
||||||
|
|
||||||
//server节点的配置
|
//server节点的配置
|
||||||
protected AnyValue serverConf;
|
protected AnyValue serverConf;
|
||||||
|
|
||||||
|
protected final String threadName;
|
||||||
|
|
||||||
//加载server节点后的拦截器
|
//加载server节点后的拦截器
|
||||||
protected NodeInterceptor interceptor;
|
protected NodeInterceptor interceptor;
|
||||||
|
|
||||||
@@ -84,11 +87,20 @@ public abstract class NodeServer {
|
|||||||
//远程模式的Service对象集合
|
//远程模式的Service对象集合
|
||||||
protected final Set<Service> remoteServices = new LinkedHashSet<>();
|
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 maxClassNameLength = 0;
|
private volatile int maxClassNameLength = 0;
|
||||||
|
|
||||||
private volatile int maxNameLength = 0;
|
private volatile int maxNameLength = 0;
|
||||||
|
|
||||||
public NodeServer(Application application, Server server) {
|
public NodeServer(Application application, Server server) {
|
||||||
|
this.threadName = Thread.currentThread().getName();
|
||||||
this.application = application;
|
this.application = application;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.resourceFactory = server.getResourceFactory();
|
this.resourceFactory = server.getResourceFactory();
|
||||||
@@ -111,7 +123,7 @@ public abstract class NodeServer {
|
|||||||
this.serverConf = config == null ? AnyValue.create() : config;
|
this.serverConf = config == null ? AnyValue.create() : config;
|
||||||
if (isSNCP()) { // SNCP协议
|
if (isSNCP()) { // SNCP协议
|
||||||
String host = this.serverConf.getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0").replace("0.0.0.0", "");
|
String host = this.serverConf.getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0").replace("0.0.0.0", "");
|
||||||
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
|
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getAddress().getHostAddress() : host, this.serverConf.getIntValue("port"));
|
||||||
this.sncpGroup = application.sncpTransportFactory.findGroupName(this.sncpAddress);
|
this.sncpGroup = application.sncpTransportFactory.findGroupName(this.sncpAddress);
|
||||||
//单向SNCP服务不需要对等group
|
//单向SNCP服务不需要对等group
|
||||||
//if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
|
//if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
|
||||||
@@ -142,9 +154,9 @@ public abstract class NodeServer {
|
|||||||
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
|
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
|
||||||
server.init(this.serverConf);
|
server.init(this.serverConf);
|
||||||
//init之后才有Executor
|
//init之后才有Executor
|
||||||
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, Executor.class, server.getExecutor());
|
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, Executor.class, server.getWorkExecutor());
|
||||||
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ExecutorService.class, server.getExecutor());
|
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ExecutorService.class, server.getWorkExecutor());
|
||||||
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ThreadPoolExecutor.class, server.getExecutor());
|
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ThreadPoolExecutor.class, server.getWorkExecutor());
|
||||||
|
|
||||||
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
|
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
|
||||||
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
||||||
@@ -154,17 +166,33 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
||||||
|
if (application.singletonrun) { //singleton模式下只加载指定的Service
|
||||||
|
final String ssc = System.getProperty("red" + "kale.singleton.serviceclass");
|
||||||
|
final String extssc = System.getProperty("red" + "kale.singleton.extserviceclasses");
|
||||||
|
if (ssc != null) {
|
||||||
|
final List<String> sscList = new ArrayList<>();
|
||||||
|
sscList.add(ssc);
|
||||||
|
if (extssc != null && !extssc.isEmpty()) {
|
||||||
|
for (String s : extssc.split(",")) {
|
||||||
|
if (!s.isEmpty()) sscList.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serviceFilter.setExpectPredicate(c -> !sscList.contains(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
||||||
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
||||||
ClassFilter otherFilter = createOtherClassFilter();
|
ClassFilter otherFilter = createOtherClassFilter();
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter, filterFilter, servletFilter, otherFilter);
|
ClassFilter.Loader.load(application.getHome(), ((application.excludelibs != null ? (application.excludelibs + ";") : "") + serverConf.getValue("excludelibs", "")).split(";"), serviceFilter, filterFilter, servletFilter, otherFilter);
|
||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
||||||
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
||||||
loadFilter(filterFilter, otherFilter);
|
if (!application.singletonrun) { //非singleton模式下才加载Filter、Servlet
|
||||||
loadServlet(servletFilter, otherFilter);
|
loadFilter(filterFilter, otherFilter);
|
||||||
|
loadServlet(servletFilter, otherFilter);
|
||||||
|
postLoadServlets();
|
||||||
|
}
|
||||||
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +211,20 @@ public abstract class NodeServer {
|
|||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
||||||
try {
|
try {
|
||||||
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
String classval = sourceConf.getValue("value");
|
||||||
|
Class type = null;
|
||||||
|
if (classval == null || classval.isEmpty()) {
|
||||||
|
Iterator<CacheSource> it = ServiceLoader.load(CacheSource.class, serverClassLoader).iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
CacheSource s = it.next();
|
||||||
|
if (s.match(sourceConf)) {
|
||||||
|
type = s.getClass();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = serverClassLoader.loadClass(classval);
|
||||||
|
}
|
||||||
if (type == DataSource.class) {
|
if (type == DataSource.class) {
|
||||||
type = DataMemorySource.class;
|
type = DataMemorySource.class;
|
||||||
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
|
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
|
||||||
@@ -256,9 +297,7 @@ public abstract class NodeServer {
|
|||||||
SncpClient client = Sncp.getSncpClient(srcService);
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
final Set<String> groups = new HashSet<>();
|
final Set<String> groups = new HashSet<>();
|
||||||
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
||||||
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
|
||||||
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,26 +308,12 @@ public abstract class NodeServer {
|
|||||||
application.dataSources.add(source);
|
application.dataSources.add(source);
|
||||||
appResFactory.register(resourceName, DataSource.class, source);
|
appResFactory.register(resourceName, DataSource.class, source);
|
||||||
|
|
||||||
SncpClient client = Sncp.getSncpClient((Service) src);
|
|
||||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
|
||||||
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
|
|
||||||
final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
|
|
||||||
final Set<String> groups = new HashSet<>();
|
|
||||||
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
|
||||||
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
|
||||||
Service cacheListenerService = Sncp.createLocalService(serverClassLoader, resourceName, DataCacheListenerService.class, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf((Service) src));
|
|
||||||
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
|
|
||||||
localServices.add(cacheListenerService);
|
|
||||||
sncpServer.consumerAccept(cacheListenerService);
|
|
||||||
rf.inject(cacheListenerService, self);
|
|
||||||
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + cacheListenerService);
|
|
||||||
}
|
|
||||||
field.set(src, source);
|
field.set(src, source);
|
||||||
rf.inject(source, self); // 给其可能包含@Resource的字段赋值;
|
rf.inject(source, self); // 给其可能包含@Resource的字段赋值;
|
||||||
//NodeServer.this.watchFactory.inject(src);
|
//NodeServer.this.watchFactory.inject(src);
|
||||||
if (source instanceof Service && needinit) ((Service) source).init(sourceConf);
|
if (source instanceof Service && needinit) ((Service) source).init(sourceConf);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "DataSource inject error", e);
|
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject error", e);
|
||||||
}
|
}
|
||||||
}, DataSource.class);
|
}, DataSource.class);
|
||||||
|
|
||||||
@@ -303,20 +328,32 @@ public abstract class NodeServer {
|
|||||||
final Service srcService = (Service) src;
|
final Service srcService = (Service) src;
|
||||||
SncpClient client = Sncp.getSncpClient(srcService);
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
final Set<String> groups = new HashSet<>();
|
|
||||||
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
|
||||||
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
|
||||||
|
|
||||||
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName);
|
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName);
|
||||||
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
|
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
|
||||||
if (sourceConf == null) {
|
if (sourceConf == null) {
|
||||||
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
|
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
|
||||||
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
|
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
|
||||||
}
|
}
|
||||||
final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
|
Class sourceType0 = CacheMemorySource.class;
|
||||||
|
if (sourceConf != null) {
|
||||||
|
String classval = sourceConf.getValue("value");
|
||||||
|
if (classval == null || classval.isEmpty()) {
|
||||||
|
Iterator<CacheSource> it = ServiceLoader.load(CacheSource.class, serverClassLoader).iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
CacheSource s = it.next();
|
||||||
|
if (s.match(sourceConf)) {
|
||||||
|
sourceType0 = s.getClass();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sourceType0 = serverClassLoader.loadClass(classval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Class sourceType = sourceType0;
|
||||||
Object source = null;
|
Object source = null;
|
||||||
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
||||||
source = (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
source = Modifier.isFinal(sourceType.getModifiers()) ? 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();
|
Type genericType = field.getGenericType();
|
||||||
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
|
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
|
||||||
Type valType = pt == null ? null : pt.getActualTypeArguments()[0];
|
Type valType = pt == null ? null : pt.getActualTypeArguments()[0];
|
||||||
@@ -361,18 +398,21 @@ public abstract class NodeServer {
|
|||||||
if (nodeService == null) {
|
if (nodeService == null) {
|
||||||
final HashSet<String> groups = new HashSet<>();
|
final HashSet<String> groups = new HashSet<>();
|
||||||
if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup);
|
if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup);
|
||||||
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null);
|
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, Sncp.getMessageAgent((Service) src), application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null);
|
||||||
(isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService);
|
(isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService);
|
||||||
|
((WebSocketNodeService) nodeService).setName(resourceName);
|
||||||
}
|
}
|
||||||
resourceFactory.inject(nodeService, self);
|
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);
|
field.set(src, nodeService);
|
||||||
if (Sncp.isRemote(nodeService)) {
|
if (Sncp.isRemote(nodeService)) {
|
||||||
remoteServices.add(nodeService);
|
remoteServices.add(nodeService);
|
||||||
} else {
|
} else {
|
||||||
if (field != null) rf.inject(nodeService); //动态加载的Service也存在按需加载的注入资源
|
rf.inject(nodeService); //动态加载的Service也存在按需加载的注入资源
|
||||||
localServices.add(nodeService);
|
localServices.add(nodeService);
|
||||||
interceptorServices.add(nodeService);
|
interceptorServices.add(nodeService);
|
||||||
if (consumer != null) consumer.accept(nodeService);
|
if (consumer != null) consumer.accept(null, nodeService);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
|
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
|
||||||
@@ -390,7 +430,7 @@ public abstract class NodeServer {
|
|||||||
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
|
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
|
||||||
if (serviceFilter == null) return;
|
if (serviceFilter == null) return;
|
||||||
final long starts = System.currentTimeMillis();
|
final long starts = System.currentTimeMillis();
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
|
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
|
||||||
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
|
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
|
||||||
final ResourceFactory appResourceFactory = application.getResourceFactory();
|
final ResourceFactory appResourceFactory = application.getResourceFactory();
|
||||||
@@ -403,12 +443,11 @@ public abstract class NodeServer {
|
|||||||
if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
|
if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
|
||||||
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
|
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
|
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
if (DataCacheListener.class.isAssignableFrom(serviceImplClass)) continue;
|
|
||||||
}
|
}
|
||||||
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
|
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
|
||||||
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
|
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
|
||||||
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
|
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
|
||||||
interceptorServices.add(oldother);
|
if (!Sncp.isRemote(oldother)) interceptorServices.add(oldother);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
|
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
|
||||||
@@ -422,16 +461,28 @@ public abstract class NodeServer {
|
|||||||
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
|
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
|
||||||
try {
|
try {
|
||||||
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的, 通常为BaseService
|
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的, 通常为BaseService
|
||||||
logger.log(Level.FINE, serviceImplClass + " cannot load because not found less one public non-final method");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
Service service;
|
||||||
boolean ws = src instanceof WebSocketServlet;
|
final boolean ws = src instanceof WebSocketServlet;
|
||||||
if (ws || localed) { //本地模式
|
if (ws || localed) { //本地模式
|
||||||
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, agent, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
||||||
} else {
|
} else {
|
||||||
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, agent, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
||||||
|
}
|
||||||
|
if (service instanceof WebSocketNodeService) {
|
||||||
|
((WebSocketNodeService) service).setName(resourceName);
|
||||||
|
if (agent != null) Sncp.setMessageAgent(service, agent);
|
||||||
}
|
}
|
||||||
final Class restype = Sncp.getResourceType(service);
|
final Class restype = Sncp.getResourceType(service);
|
||||||
if (rf.find(resourceName, restype) == null) {
|
if (rf.find(resourceName, restype) == null) {
|
||||||
@@ -441,11 +492,12 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
if (Sncp.isRemote(service)) {
|
if (Sncp.isRemote(service)) {
|
||||||
remoteServices.add(service);
|
remoteServices.add(service);
|
||||||
|
if (agent != null) sncpRemoteAgents.put(agent.getName(), agent);
|
||||||
} else {
|
} else {
|
||||||
if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
|
if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
|
||||||
localServices.add(service);
|
localServices.add(service);
|
||||||
interceptorServices.add(service);
|
interceptorServices.add(service);
|
||||||
if (consumer != null) consumer.accept(service);
|
if (consumer != null) consumer.accept(agent, service);
|
||||||
}
|
}
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
throw ex;
|
throw ex;
|
||||||
@@ -478,12 +530,18 @@ public abstract class NodeServer {
|
|||||||
|
|
||||||
if (sb != null) {
|
if (sb != null) {
|
||||||
remoteServices.forEach(y -> {
|
remoteServices.forEach(y -> {
|
||||||
sb.append(threadName).append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" load and inject").append(LINE_SEPARATOR);
|
sb.append(localThreadName).append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" load and inject").append(LINE_SEPARATOR);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isSNCP() && !sncpRemoteAgents.isEmpty()) {
|
||||||
|
sncpRemoteAgents.values().forEach(agent -> {
|
||||||
|
// agent.putSncpResp((NodeSncpServer) this);
|
||||||
|
// agent.startSncpRespConsumer();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//----------------- init -----------------
|
//----------------- init -----------------
|
||||||
List<Service> swlist = new ArrayList<>(localServices);
|
List<Service> swlist = new ArrayList<>(localServices);
|
||||||
Collections.sort(swlist, (o1, o2) -> {
|
swlist.sort((o1, o2) -> {
|
||||||
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
||||||
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
||||||
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
@@ -495,21 +553,25 @@ public abstract class NodeServer {
|
|||||||
localServices.clear();
|
localServices.clear();
|
||||||
localServices.addAll(swlist);
|
localServices.addAll(swlist);
|
||||||
//this.loadPersistData();
|
//this.loadPersistData();
|
||||||
|
long preinits = System.currentTimeMillis();
|
||||||
|
preInitServices(localServices, remoteServices);
|
||||||
|
long preinite = System.currentTimeMillis() - preinits;
|
||||||
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
|
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
|
||||||
localServices.stream().forEach(y -> {
|
localServices.stream().forEach(y -> {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
y.init(Sncp.getConf(y));
|
y.init(Sncp.getConf(y));
|
||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
|
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
|
||||||
if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
|
if (slist != null) slist.add(new StringBuilder().append(localThreadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
|
||||||
});
|
});
|
||||||
if (slist != null && sb != null) {
|
if (slist != null && sb != null) {
|
||||||
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
|
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
|
||||||
for (String s : wlist) {
|
for (String s : wlist) {
|
||||||
sb.append(s);
|
sb.append(s);
|
||||||
}
|
}
|
||||||
sb.append(threadName).append("All Services load cost " + (System.currentTimeMillis() - starts) + " ms" + LINE_SEPARATOR);
|
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());
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,6 +580,44 @@ public abstract class NodeServer {
|
|||||||
maxClassNameLength = Math.max(maxClassNameLength, Sncp.getResourceType(y).getName().length() + 1);
|
maxClassNameLength = Math.max(maxClassNameLength, Sncp.getResourceType(y).getName().length() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Service.init执行之前调用
|
||||||
|
protected void preInitServices(Set<Service> localServices, Set<Service> remoteServices) {
|
||||||
|
final ClusterAgent cluster = application.clusterAgent;
|
||||||
|
if (cluster == null) return;
|
||||||
|
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.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 (!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<Filter> createFilterClassFilter();
|
||||||
|
|
||||||
protected abstract ClassFilter<Servlet> createServletClassFilter();
|
protected abstract ClassFilter<Servlet> createServletClassFilter();
|
||||||
@@ -548,22 +648,24 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
cf = null;
|
cf = null;
|
||||||
for (AnyValue list : proplist) {
|
for (AnyValue list : proplist) {
|
||||||
DefaultAnyValue prop = null;
|
AnyValue.DefaultAnyValue prop = null;
|
||||||
String sc = list.getValue("groups");
|
String sc = list.getValue("groups");
|
||||||
|
String mq = list.getValue("mq");
|
||||||
if (sc != null) {
|
if (sc != null) {
|
||||||
sc = sc.trim();
|
sc = sc.trim();
|
||||||
if (sc.endsWith(";")) sc = sc.substring(0, sc.length() - 1);
|
if (sc.endsWith(";")) sc = sc.substring(0, sc.length() - 1);
|
||||||
}
|
}
|
||||||
if (sc == null) sc = localGroup;
|
if (sc == null) sc = localGroup;
|
||||||
if (sc != null) {
|
if (sc != null || mq != null) {
|
||||||
prop = new AnyValue.DefaultAnyValue();
|
prop = new AnyValue.DefaultAnyValue();
|
||||||
prop.addValue("groups", sc);
|
if (sc != null) prop.addValue("groups", sc);
|
||||||
|
if (mq != null) prop.addValue("mq", mq);
|
||||||
}
|
}
|
||||||
ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop);
|
ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop);
|
||||||
for (AnyValue av : list.getAnyValues(property)) { // <service>、<filter>、<servlet> 节点
|
for (AnyValue av : list.getAnyValues(property)) { // <service>、<filter>、<servlet> 节点
|
||||||
final AnyValue[] items = av.getAnyValues("property");
|
final AnyValue[] items = av.getAnyValues("property");
|
||||||
if (av instanceof DefaultAnyValue && items.length > 0) { //存在 <property>节点
|
if (av instanceof AnyValue.DefaultAnyValue && items.length > 0) { //存在 <property>节点
|
||||||
DefaultAnyValue dav = DefaultAnyValue.create();
|
AnyValue.DefaultAnyValue dav = AnyValue.DefaultAnyValue.create();
|
||||||
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
|
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
|
||||||
if (strings != null) { //将<service>、<filter>、<servlet>节点的属性值传给dav
|
if (strings != null) { //将<service>、<filter>、<servlet>节点的属性值传给dav
|
||||||
for (AnyValue.Entry<String> en : strings) {
|
for (AnyValue.Entry<String> en : strings) {
|
||||||
@@ -576,7 +678,7 @@ public abstract class NodeServer {
|
|||||||
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
|
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DefaultAnyValue ps = DefaultAnyValue.create();
|
AnyValue.DefaultAnyValue ps = AnyValue.DefaultAnyValue.create();
|
||||||
for (AnyValue item : items) {
|
for (AnyValue item : items) {
|
||||||
ps.addValue(item.getValue("name"), item.getValue("value"));
|
ps.addValue(item.getValue("name"), item.getValue("value"));
|
||||||
}
|
}
|
||||||
@@ -612,6 +714,10 @@ public abstract class NodeServer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Application getApplication() {
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
public ResourceFactory getResourceFactory() {
|
public ResourceFactory getResourceFactory() {
|
||||||
return resourceFactory;
|
return resourceFactory;
|
||||||
}
|
}
|
||||||
@@ -645,12 +751,14 @@ public abstract class NodeServer {
|
|||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
if (interceptor != null) interceptor.preStart(this);
|
if (interceptor != null) interceptor.preStart(this);
|
||||||
server.start();
|
server.start();
|
||||||
|
postStartServer(localServices, remoteServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() throws IOException {
|
public void shutdown() throws IOException {
|
||||||
if (interceptor != null) interceptor.preShutdown(this);
|
if (interceptor != null) interceptor.preShutdown(this);
|
||||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
final boolean finest = logger.isLoggable(Level.FINEST);
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
preDestroyServices(localServices, remoteServices);
|
||||||
localServices.forEach(y -> {
|
localServices.forEach(y -> {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
if (finest) logger.finest(y + " is destroying");
|
if (finest) logger.finest(y + " is destroying");
|
||||||
@@ -665,6 +773,42 @@ public abstract class NodeServer {
|
|||||||
server.shutdown();
|
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, maxClassNameLength)).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() {
|
public <T extends Server> T getServer() {
|
||||||
return (T) server;
|
return (T) server;
|
||||||
}
|
}
|
||||||
@@ -681,4 +825,7 @@ public abstract class NodeServer {
|
|||||||
return new LinkedHashSet<>(remoteServices);
|
return new LinkedHashSet<>(remoteServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getThreadName() {
|
||||||
|
return this.threadName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ import java.net.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.redkale.boot.ClassFilter.FilterEntry;
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.mq.MessageAgent;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.sncp.*;
|
import org.redkale.net.sncp.*;
|
||||||
import org.redkale.service.Service;
|
import org.redkale.service.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
import org.redkale.util.AnyValue.DefaultAnyValue;
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ import org.redkale.util.AnyValue.DefaultAnyValue;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@NodeProtocol({"SNCP"})
|
@NodeProtocol("SNCP")
|
||||||
public class NodeSncpServer extends NodeServer {
|
public class NodeSncpServer extends NodeServer {
|
||||||
|
|
||||||
protected final SncpServer sncpServer;
|
protected final SncpServer sncpServer;
|
||||||
@@ -32,14 +33,15 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
private NodeSncpServer(Application application, AnyValue serconf) {
|
private NodeSncpServer(Application application, AnyValue serconf) {
|
||||||
super(application, createServer(application, serconf));
|
super(application, createServer(application, serconf));
|
||||||
this.sncpServer = (SncpServer) this.server;
|
this.sncpServer = (SncpServer) this.server;
|
||||||
this.consumer = sncpServer == null ? null : x -> sncpServer.addSncpServlet(x);
|
this.consumer = sncpServer == null || application.singletonrun ? null : (agent, x) -> {//singleton模式下不生成SncpServlet
|
||||||
|
if (x.getClass().getAnnotation(Local.class) != null) return;
|
||||||
|
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) {
|
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);
|
return new NodeSncpServer(application, serconf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,8 +54,8 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
return sncpServer == null ? null : sncpServer.getSocketAddress();
|
return sncpServer == null ? null : sncpServer.getSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consumerAccept(Service service) {
|
public void consumerAccept(MessageAgent messageAgent, Service service) {
|
||||||
if (this.consumer != null) this.consumer.accept(service);
|
if (this.consumer != null) this.consumer.accept(messageAgent, service);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -62,11 +64,11 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
if (sncpServer == null) return; //调试时server才可能为null
|
if (sncpServer == null) return; //调试时server才可能为null
|
||||||
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : 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();
|
List<SncpServlet> servlets = sncpServer.getSncpServlets();
|
||||||
Collections.sort(servlets);
|
Collections.sort(servlets);
|
||||||
for (SncpServlet en : servlets) {
|
for (SncpServlet en : servlets) {
|
||||||
if (sb != null) sb.append(threadName).append(" 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());
|
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
|
||||||
}
|
}
|
||||||
@@ -88,7 +90,7 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
|
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
|
||||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||||
for (FilterEntry<? extends Filter> en : list) {
|
for (FilterEntry<? extends Filter> en : list) {
|
||||||
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
|
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
|
||||||
@@ -97,7 +99,7 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
resourceFactory.inject(filter, this);
|
resourceFactory.inject(filter, this);
|
||||||
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
||||||
this.sncpServer.addSncpFilter(filter, filterConf);
|
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());
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import org.redkale.watch.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@NodeProtocol({"WATCH"})
|
@NodeProtocol("WATCH")
|
||||||
public class NodeWatchServer extends NodeHttpServer {
|
public class NodeWatchServer extends NodeHttpServer {
|
||||||
|
|
||||||
public NodeWatchServer(Application application, AnyValue serconf) {
|
public NodeWatchServer(Application application, AnyValue serconf) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class FilterWatchService extends AbstractWatchService {
|
|||||||
@Resource
|
@Resource
|
||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
|
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
|
||||||
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
|
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
|
||||||
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
||||||
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
|
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class ServerWatchService extends AbstractWatchService {
|
|||||||
return new RetResult(rs);
|
return new RetResult(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "changeaddress", comment = "更改Server的监听地址和端口")
|
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
|
||||||
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
|
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
|
||||||
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
|
@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 (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
|
||||||
@@ -81,7 +81,7 @@ public class ServerWatchService extends AbstractWatchService {
|
|||||||
protocol += "/HTTP";
|
protocol += "/HTTP";
|
||||||
} else {
|
} else {
|
||||||
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
|
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
|
||||||
if (np != null && np.value().length > 0) protocol += "/" + np.value()[0];
|
protocol += "/" + np.value();
|
||||||
}
|
}
|
||||||
rs.put("name", server.getName());
|
rs.put("name", server.getName());
|
||||||
rs.put("protocol", protocol);
|
rs.put("protocol", protocol);
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
@RestConvert(type = void.class)
|
@RestConvert(type = void.class)
|
||||||
@RestMapping(name = "setfield", auth = false, comment = "设置Service中指定字段的内容")
|
@RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容")
|
||||||
public RetResult setfield(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult setField(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
@RestParam(name = "field", comment = "字段名") String field,
|
@RestParam(name = "field", comment = "字段名") String field,
|
||||||
@RestParam(name = "value", comment = "字段值") String value) {
|
@RestParam(name = "value", comment = "字段值") String value) {
|
||||||
@@ -65,8 +65,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RestConvert(type = void.class)
|
@RestConvert(type = void.class)
|
||||||
@RestMapping(name = "getfield", auth = false, comment = "查询Service中指定字段的内容")
|
@RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容")
|
||||||
public RetResult getfield(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult getField(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
@RestParam(name = "field", comment = "字段名") String field) {
|
@RestParam(name = "field", comment = "字段名") String field) {
|
||||||
if (name == null) name = "";
|
if (name == null) name = "";
|
||||||
@@ -98,8 +98,8 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RestConvert(type = void.class)
|
@RestConvert(type = void.class)
|
||||||
@RestMapping(name = "runmethod", auth = false, comment = "调用Service中指定方法")
|
@RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法")
|
||||||
public RetResult runmethod(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult runMethod(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
@RestParam(name = "method", comment = "Service的方法名") String method,
|
@RestParam(name = "method", comment = "Service的方法名") String method,
|
||||||
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
|
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
|
||||||
@@ -169,28 +169,28 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "load", auth = false, comment = "动态增加Service")
|
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
|
||||||
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
|
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
//待开发
|
//待开发
|
||||||
return RetResult.success();
|
return RetResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "reload", auth = false, comment = "重新加载Service")
|
@RestMapping(name = "reloadService", auth = false, comment = "重新加载Service")
|
||||||
public RetResult reloadService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult reloadService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
//待开发
|
//待开发
|
||||||
return RetResult.success();
|
return RetResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "stop", auth = false, comment = "动态停止Service")
|
@RestMapping(name = "stopService", auth = false, comment = "动态停止Service")
|
||||||
public RetResult stopService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult stopService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
//待开发
|
//待开发
|
||||||
return RetResult.success();
|
return RetResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestMapping(name = "find", auth = false, comment = "查找Service")
|
@RestMapping(name = "findService", auth = false, comment = "查找Service")
|
||||||
public RetResult find(@RestParam(name = "name", comment = "Service的资源名") String name,
|
public RetResult find(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
//待开发
|
//待开发
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ public class ServletWatchService extends AbstractWatchService {
|
|||||||
@Resource
|
@Resource
|
||||||
protected TransportFactory transportFactory;
|
protected TransportFactory transportFactory;
|
||||||
//
|
//
|
||||||
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
|
// @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet")
|
||||||
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
// //待开发
|
// //待开发
|
||||||
// return RetResult.success();
|
// return RetResult.success();
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// @RestMapping(name = "stop", auth = false, comment = "动态停止Servlet")
|
// @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet")
|
||||||
// public RetResult stopServlet(String type) {
|
// public RetResult stopServlet(String type) {
|
||||||
// //待开发
|
// //待开发
|
||||||
// return RetResult.success();
|
// return RetResult.success();
|
||||||
|
|||||||
@@ -72,15 +72,6 @@ public class TransportWatchService extends AbstractWatchService {
|
|||||||
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
||||||
client.getRemoteGroupTransport().addRemoteAddresses(address);
|
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);
|
DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port);
|
||||||
@@ -114,15 +105,6 @@ public class TransportWatchService extends AbstractWatchService {
|
|||||||
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
||||||
client.getRemoteGroupTransport().removeRemoteAddresses(address);
|
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")) {
|
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
|
||||||
|
|||||||
328
src/org/redkale/cluster/ClusterAgent.java
Normal file
328
src/org/redkale/cluster/ClusterAgent.java
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
* 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 match(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;
|
||||||
|
register(ns, protocol, service);
|
||||||
|
ClusterEntry htentry = new ClusterEntry(ns, protocol, service);
|
||||||
|
localEntrys.put(htentry.serviceid, htentry);
|
||||||
|
if (protocol.toLowerCase().startsWith("http")) {
|
||||||
|
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
|
||||||
|
if (mmc != null) {
|
||||||
|
register(ns, "mqtp", service);
|
||||||
|
ClusterEntry mqentry = new ClusterEntry(ns, "mqtp", service);
|
||||||
|
localEntrys.put(mqentry.serviceid, mqentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//远程模式加载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;
|
||||||
|
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 void 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 ScheduledFuture checkScheduledFuture;
|
||||||
|
|
||||||
|
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;
|
||||||
|
this.address = ns.getSocketAddress();
|
||||||
|
this.serviceref = new WeakReference(service);
|
||||||
|
Server server = ns.getServer();
|
||||||
|
this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_PROTOCOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/org/redkale/convert/AnyDecoder.java
Normal file
64
src/org/redkale/convert/AnyDecoder.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.convert.Reader.ValueType;
|
||||||
|
import static org.redkale.convert.Reader.ValueType.MAP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对不明类型的对象进行反序列化。 <br>
|
||||||
|
* <b>注意: 目前只支持文本格式</b> <br>
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class AnyDecoder implements Decodeable<Reader, Object> {
|
||||||
|
|
||||||
|
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
|
||||||
|
|
||||||
|
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
|
||||||
|
|
||||||
|
protected final Decodeable<Reader, String> stringDecoder;
|
||||||
|
|
||||||
|
protected final CollectionDecoder collectionDecoder;
|
||||||
|
|
||||||
|
protected final MapDecoder mapDecoder;
|
||||||
|
|
||||||
|
public AnyDecoder(final ConvertFactory factory) {
|
||||||
|
this.stringDecoder = factory.loadDecoder(String.class);
|
||||||
|
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
|
||||||
|
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertFrom(Reader in) {
|
||||||
|
ValueType vt = in.readType();
|
||||||
|
if (vt == null) return null;
|
||||||
|
switch (vt) {
|
||||||
|
case ARRAY:
|
||||||
|
return this.collectionDecoder.convertFrom(in);
|
||||||
|
case MAP:
|
||||||
|
return this.mapDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
return this.stringDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return void.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ package org.redkale.convert;
|
|||||||
import org.redkale.util.Creator;
|
import org.redkale.util.Creator;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection的反序列化操作类 <br>
|
* Collection的反序列化操作类 <br>
|
||||||
@@ -60,6 +60,17 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//仅供类似JsonAnyDecoder这种动态创建使用, 不得调用 factory.register
|
||||||
|
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
|
||||||
|
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
|
||||||
|
Objects.requireNonNull(componentDecoder);
|
||||||
|
this.type = type;
|
||||||
|
this.componentType = componentType;
|
||||||
|
this.creator = creator;
|
||||||
|
this.componentDecoder = componentDecoder;
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<T> convertFrom(Reader in) {
|
public Collection<T> convertFrom(Reader in) {
|
||||||
return convertFrom(in, null);
|
return convertFrom(in, null);
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ package org.redkale.convert;
|
|||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.*;
|
||||||
|
import org.redkale.util.Attribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化/反序列化操作类
|
* 序列化/反序列化操作类
|
||||||
@@ -31,12 +32,32 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
|||||||
return this.factory;
|
return this.factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S configWrite(S writer) {
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||||
|
writer.objFieldFunc = objFieldFunc;
|
||||||
|
writer.objExtFunc = objExtFunc;
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
|
||||||
|
|
||||||
|
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
|
||||||
|
|
||||||
public abstract boolean isBinary();
|
public abstract boolean isBinary();
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
|
||||||
|
|
||||||
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
||||||
|
|
||||||
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
||||||
|
|
||||||
|
public abstract byte[] convertToBytes(final Object value);
|
||||||
|
|
||||||
|
public abstract byte[] convertToBytes(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 Object value);
|
||||||
|
|
||||||
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value);
|
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value);
|
||||||
|
|||||||
@@ -89,4 +89,9 @@ public final class ConvertColumnEntry {
|
|||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,8 +91,11 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
|
|
||||||
this.register(Number.class, NumberSimpledCoder.instance);
|
this.register(Number.class, NumberSimpledCoder.instance);
|
||||||
this.register(String.class, StringSimpledCoder.instance);
|
this.register(String.class, StringSimpledCoder.instance);
|
||||||
|
this.register(StringWrapper.class, StringWrapperSimpledCoder.instance);
|
||||||
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
||||||
|
this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance);
|
||||||
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
||||||
|
this.register(java.time.Duration.class, DurationSimpledCoder.instance);
|
||||||
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
|
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
|
||||||
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
|
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
|
||||||
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
||||||
@@ -130,6 +133,54 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
try {
|
||||||
|
Class sqldateClass = Class.forName("java.sql.Date");
|
||||||
|
this.register(sqldateClass, new SimpledCoder<R, W, java.sql.Date>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, java.sql.Date value) {
|
||||||
|
out.writeSmallString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Date convertFrom(R in) {
|
||||||
|
String t = in.readSmallString();
|
||||||
|
return t == null ? null : java.sql.Date.valueOf(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Class sqltimeClass = Class.forName("java.sql.Time");
|
||||||
|
this.register(sqltimeClass, new SimpledCoder<R, W, java.sql.Time>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, java.sql.Time value) {
|
||||||
|
out.writeSmallString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Time convertFrom(R in) {
|
||||||
|
String t = in.readSmallString();
|
||||||
|
return t == null ? null : java.sql.Time.valueOf(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Class timestampClass = Class.forName("java.sql.Timestamp");
|
||||||
|
this.register(timestampClass, new SimpledCoder<R, W, java.sql.Timestamp>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, java.sql.Timestamp value) {
|
||||||
|
out.writeSmallString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Timestamp convertFrom(R in) {
|
||||||
|
String t = in.readSmallString();
|
||||||
|
return t == null ? null : java.sql.Timestamp.valueOf(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
} catch (Throwable t) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,15 +270,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvertColumnEntry findRef(AccessibleObject element) {
|
public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) {
|
||||||
if (element == null) return null;
|
if (element == null) return null;
|
||||||
ConvertColumnEntry en = this.columnEntrys.get(element);
|
ConvertColumnEntry en = this.columnEntrys.get(element);
|
||||||
Set<String> onlyColumns = null;
|
Set<String> onlyColumns = ignoreAlls.get(clazz);
|
||||||
if (element instanceof Method) {
|
|
||||||
onlyColumns = ignoreAlls.get(((Method) element).getDeclaringClass());
|
|
||||||
} else if (element instanceof Field) {
|
|
||||||
onlyColumns = ignoreAlls.get(((Field) element).getDeclaringClass());
|
|
||||||
}
|
|
||||||
if (en != null && onlyColumns == null) return en;
|
if (en != null && onlyColumns == null) return en;
|
||||||
final ConvertType ct = this.getConvertType();
|
final ConvertType ct = this.getConvertType();
|
||||||
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
|
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
|
||||||
@@ -254,8 +300,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
for (ConvertColumn ref : ccs) {
|
for (ConvertColumn ref : ccs) {
|
||||||
if (ref.type().contains(ct)) {
|
if (ref.type().contains(ct)) {
|
||||||
|
String realName = ref.name().isEmpty() ? fieldName : ref.name();
|
||||||
if (onlyColumns != null && fieldName != null) {
|
if (onlyColumns != null && fieldName != null) {
|
||||||
String realName = ref.name().isEmpty() ? fieldName : ref.name();
|
|
||||||
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
|
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
|
||||||
}
|
}
|
||||||
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
|
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
|
||||||
@@ -263,7 +309,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
entry.setIgnore(false);
|
entry.setIgnore(false);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
if (skipIgnores.isEmpty()) return entry;
|
if (skipIgnores.isEmpty()) {
|
||||||
|
if (onlyColumns != null && realName != null && onlyColumns.contains(realName)) entry.setIgnore(false);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
|
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -406,37 +455,59 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void registerIgnoreAll(final Class type, Collection<String> excludeColumns) {
|
||||||
|
Set<String> set = ignoreAlls.get(type);
|
||||||
|
if (set == null) {
|
||||||
|
ignoreAlls.put(type, new HashSet<>(excludeColumns));
|
||||||
|
} else {
|
||||||
|
set.addAll(new ArrayList(excludeColumns));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final void register(final Class type, boolean ignore, String... columns) {
|
public final void register(final Class type, boolean ignore, String... columns) {
|
||||||
for (String column : columns) {
|
for (String column : columns) {
|
||||||
register(type, column, new ConvertColumnEntry(column, ignore));
|
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void register(final Class type, boolean ignore, Collection<String> columns) {
|
||||||
|
for (String column : columns) {
|
||||||
|
register(type, column, new ConvertColumnEntry(column, ignore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean register(final Class type, String column, String alias) {
|
public final boolean register(final Class type, String column, String alias) {
|
||||||
return register(type, column, new ConvertColumnEntry(alias));
|
return register(type, column, new ConvertColumnEntry(alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean register(final Class type, String column, ConvertColumnEntry entry) {
|
public final boolean register(final Class type, String column, ConvertColumnEntry entry) {
|
||||||
if (type == null || column == null || entry == null) return false;
|
if (type == null || column == null || entry == null) return false;
|
||||||
|
Field field = null;
|
||||||
try {
|
try {
|
||||||
final Field field = type.getDeclaredField(column);
|
field = type.getDeclaredField(column);
|
||||||
String get = "get";
|
|
||||||
if (field.getType() == boolean.class || field.getType() == Boolean.class) get = "is";
|
|
||||||
char[] cols = column.toCharArray();
|
|
||||||
cols[0] = Character.toUpperCase(cols[0]);
|
|
||||||
String col2 = new String(cols);
|
|
||||||
try {
|
|
||||||
register(type.getMethod(get + col2), entry);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
register(type.getMethod("set" + col2, field.getType()), entry);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
}
|
|
||||||
return register(field, entry);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
String get = "get";
|
||||||
|
if (field != null && (field.getType() == boolean.class || field.getType() == Boolean.class)) get = "is";
|
||||||
|
char[] cols = column.toCharArray();
|
||||||
|
cols[0] = Character.toUpperCase(cols[0]);
|
||||||
|
final String bigColumn = new String(cols);
|
||||||
|
try {
|
||||||
|
register(type.getMethod(get + bigColumn), entry);
|
||||||
|
} catch (NoSuchMethodException mex) {
|
||||||
|
if (get.length() >= 3) { //get
|
||||||
|
try {
|
||||||
|
register(type.getMethod("is" + bigColumn), entry);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
register(type.getMethod("set" + bigColumn, field.getType()), entry);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
return field == null ? true : register(field, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final <E> boolean register(final AccessibleObject field, final ConvertColumnEntry entry) {
|
public final <E> boolean register(final AccessibleObject field, final ConvertColumnEntry entry) {
|
||||||
@@ -604,6 +675,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
decoder = od;
|
decoder = od;
|
||||||
} else if (!clazz.getName().startsWith("java.")
|
} else if (!clazz.getName().startsWith("java.")
|
||||||
|| java.net.HttpCookie.class == clazz
|
|| java.net.HttpCookie.class == clazz
|
||||||
|
|| java.util.AbstractMap.SimpleEntry.class == clazz
|
||||||
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
||||||
Decodeable simpleCoder = null;
|
Decodeable simpleCoder = null;
|
||||||
for (final Method method : clazz.getDeclaredMethods()) {
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
@@ -687,7 +759,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
encoder = new OptionalCoder(this, type);
|
encoder = new OptionalCoder(this, type);
|
||||||
} else if (clazz == Object.class) {
|
} else if (clazz == Object.class) {
|
||||||
return (Encodeable<W, E>) this.anyEncoder;
|
return (Encodeable<W, E>) this.anyEncoder;
|
||||||
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz) {
|
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz
|
||||||
|
|| java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
|
||||||
Encodeable simpleCoder = null;
|
Encodeable simpleCoder = null;
|
||||||
for (final Method method : clazz.getDeclaredMethods()) {
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
if (!Modifier.isStatic(method.getModifiers())) continue;
|
if (!Modifier.isStatic(method.getModifiers())) continue;
|
||||||
|
|||||||
102
src/org/redkale/convert/ConvertField.java
Normal file
102
src/org/redkale/convert/ConvertField.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newConvert参数中的Function返回结果的数据类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class ConvertField implements Serializable {
|
||||||
|
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
protected Type type;
|
||||||
|
|
||||||
|
protected int position;
|
||||||
|
|
||||||
|
protected Object value;
|
||||||
|
|
||||||
|
public ConvertField() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, int position, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.position = position;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, Type type, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertField(String name, Type type, int position, Object value) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.position = position;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConvertField[] ofArray(Object... items) {
|
||||||
|
int len = items.length / 2;
|
||||||
|
ConvertField[] rs = new ConvertField[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]);
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(int position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonConvert.root().convertTo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,8 +17,10 @@ public enum ConvertType {
|
|||||||
|
|
||||||
JSON(1),
|
JSON(1),
|
||||||
BSON(2),
|
BSON(2),
|
||||||
DIY(64),
|
PROTOBUF(64),
|
||||||
ALL(127);
|
PROTOBUF_JSON(64 + 1),
|
||||||
|
DIY(256),
|
||||||
|
ALL(1023);
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
|
|
||||||
@@ -26,8 +28,19 @@ public enum ConvertType {
|
|||||||
this.value = v;
|
this.value = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean contains(ConvertType type) {
|
public boolean contains(ConvertType type) {
|
||||||
if (type == null) return false;
|
if (type == null) return false;
|
||||||
return this.value >= type.value && (this.value & type.value) > 0;
|
return this.value >= type.value && (this.value & type.value) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ConvertType find(int value) {
|
||||||
|
for (ConvertType t : ConvertType.values()) {
|
||||||
|
if (value == t.value) return t;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package org.redkale.convert;
|
|||||||
import org.redkale.util.Creator;
|
import org.redkale.util.Creator;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map的反序列化操作类 <br>
|
* Map的反序列化操作类 <br>
|
||||||
@@ -74,6 +74,20 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//仅供类似JsonAnyDecoder这种动态创建使用, 不得调用 factory.register
|
||||||
|
public MapDecoder(final ConvertFactory factory, Type type, Type keyType, Type valueType,
|
||||||
|
Creator<Map<K, V>> creator, final Decodeable<Reader, K> keyDecoder, Decodeable<Reader, V> valueDecoder) {
|
||||||
|
Objects.requireNonNull(keyDecoder);
|
||||||
|
Objects.requireNonNull(valueDecoder);
|
||||||
|
this.type = type;
|
||||||
|
this.keyType = keyType;
|
||||||
|
this.valueType = valueType;
|
||||||
|
this.creator = creator;
|
||||||
|
this.keyDecoder = keyDecoder;
|
||||||
|
this.valueDecoder = valueDecoder;
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<K, V> convertFrom(Reader in) {
|
public Map<K, V> convertFrom(Reader in) {
|
||||||
return convertFrom(in, null);
|
return convertFrom(in, null);
|
||||||
|
|||||||
@@ -94,14 +94,14 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
for (final Field field : clazz.getFields()) {
|
for (final Field field : clazz.getFields()) {
|
||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
if (factory.isConvertDisabled(field)) continue;
|
if (factory.isConvertDisabled(field)) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(clazz, field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
||||||
if (fieldCoder == null) {
|
if (fieldCoder == null) {
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
||||||
fieldCoder = factory.loadDecoder(t);
|
fieldCoder = factory.loadDecoder(t);
|
||||||
}
|
}
|
||||||
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), fieldCoder);
|
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, field, null, null), fieldCoder);
|
||||||
if (ref != null) member.index = ref.getIndex();
|
if (ref != null) member.index = ref.getIndex();
|
||||||
list.add(member);
|
list.add(member);
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(clazz, method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
|
|
||||||
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
||||||
@@ -131,7 +131,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
|
||||||
fieldCoder = factory.loadDecoder(t);
|
fieldCoder = factory.loadDecoder(t);
|
||||||
}
|
}
|
||||||
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), fieldCoder);
|
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, null, method), fieldCoder);
|
||||||
if (ref != null) member.index = ref.getIndex();
|
if (ref != null) member.index = ref.getIndex();
|
||||||
list.add(member);
|
list.add(member);
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
try {
|
try {
|
||||||
Field f = clazz.getDeclaredField(constructorField);
|
Field f = clazz.getDeclaredField(constructorField);
|
||||||
Type t = TypeToken.createClassType(f.getGenericType(), this.type);
|
Type t = TypeToken.createClassType(f.getGenericType(), this.type);
|
||||||
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t)));
|
list.add(new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, f, null, null), factory.loadDecoder(t)));
|
||||||
} catch (NoSuchFieldException nsfe) { //不存在field, 可能存在getter方法
|
} catch (NoSuchFieldException nsfe) { //不存在field, 可能存在getter方法
|
||||||
char[] fs = constructorField.toCharArray();
|
char[] fs = constructorField.toCharArray();
|
||||||
fs[0] = Character.toUpperCase(fs[0]);
|
fs[0] = Character.toUpperCase(fs[0]);
|
||||||
@@ -161,7 +161,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
|||||||
getter = clazz.getMethod("is" + mn);
|
getter = clazz.getMethod("is" + mn);
|
||||||
}
|
}
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(getter.getGenericParameterTypes()[0], this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(getter.getGenericParameterTypes()[0], this.type), this.type);
|
||||||
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
|
list.add(new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, getter, null), factory.loadDecoder(t)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,14 +75,14 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
for (final Field field : clazz.getFields()) {
|
for (final Field field : clazz.getFields()) {
|
||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
if (factory.isConvertDisabled(field)) continue;
|
if (factory.isConvertDisabled(field)) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(clazz, field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
|
||||||
if (fieldCoder == null) {
|
if (fieldCoder == null) {
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
|
||||||
fieldCoder = factory.loadEncoder(t);
|
fieldCoder = factory.loadEncoder(t);
|
||||||
}
|
}
|
||||||
EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), fieldCoder);
|
EnMember member = new EnMember(createAttribute(factory, type, clazz, field, null, null), fieldCoder);
|
||||||
if (ref != null) member.index = ref.getIndex();
|
if (ref != null) member.index = ref.getIndex();
|
||||||
list.add(member);
|
list.add(member);
|
||||||
}
|
}
|
||||||
@@ -104,14 +104,14 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(clazz, method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
|
||||||
if (fieldCoder == null) {
|
if (fieldCoder == null) {
|
||||||
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
|
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
|
||||||
fieldCoder = factory.loadEncoder(t);
|
fieldCoder = factory.loadEncoder(t);
|
||||||
}
|
}
|
||||||
EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), fieldCoder);
|
EnMember member = new EnMember(createAttribute(factory, type, clazz, null, method, null), fieldCoder);
|
||||||
if (ref != null) member.index = ref.getIndex();
|
if (ref != null) member.index = ref.getIndex();
|
||||||
list.add(member);
|
list.add(member);
|
||||||
}
|
}
|
||||||
@@ -164,9 +164,22 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (out.writeObjectB(value) < 0) {
|
if (out.writeObjectB(value) < 0) {
|
||||||
|
int maxPosition = 0;
|
||||||
for (EnMember member : members) {
|
for (EnMember member : members) {
|
||||||
|
maxPosition = member.getPosition();
|
||||||
out.writeObjectField(member, value);
|
out.writeObjectField(member, value);
|
||||||
}
|
}
|
||||||
|
if (out.objExtFunc != null) {
|
||||||
|
ConvertField[] extFields = out.objExtFunc.apply(value);
|
||||||
|
if (extFields != null) {
|
||||||
|
Encodeable<W, ?> anyEncoder = factory.getAnyEncoder();
|
||||||
|
for (ConvertField en : extFields) {
|
||||||
|
if (en == null) continue;
|
||||||
|
maxPosition++;
|
||||||
|
out.writeObjectField(en.getName(), en.getType(), Math.max(en.getPosition(), maxPosition), anyEncoder, en.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.writeObjectE(value);
|
out.writeObjectE(value);
|
||||||
}
|
}
|
||||||
@@ -250,33 +263,33 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
|
static Attribute createAttribute(final ConvertFactory factory, Type realType, Class clazz, final Field field, final Method getter, final Method setter) {
|
||||||
String fieldalias;
|
String fieldalias;
|
||||||
if (field != null) { // public field
|
if (field != null) { // public field
|
||||||
ConvertColumnEntry ref = factory.findRef(field);
|
ConvertColumnEntry ref = factory.findRef(clazz, field);
|
||||||
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
|
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
|
||||||
} else if (getter != null) {
|
} else if (getter != null) {
|
||||||
ConvertColumnEntry ref = factory.findRef(getter);
|
ConvertColumnEntry ref = factory.findRef(clazz, getter);
|
||||||
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
|
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
try {
|
try {
|
||||||
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
|
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
||||||
} else { // setter != null
|
} else { // setter != null
|
||||||
ConvertColumnEntry ref = factory.findRef(setter);
|
ConvertColumnEntry ref = factory.findRef(clazz, setter);
|
||||||
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
|
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
try {
|
try {
|
||||||
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
|
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
|
||||||
}
|
}
|
||||||
return Attribute.create(clazz, fieldalias, field, getter, setter);
|
return Attribute.create(realType, clazz, fieldalias, null, field, getter, setter, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class OptionalCoder<R extends Reader, W extends Writer, T> extends SimpledCoder<R, W, Optional<T>> {
|
public class OptionalCoder<R extends Reader, W extends Writer, T> extends SimpledCoder<R, W, Optional<T>> {
|
||||||
|
|
||||||
private final Type type;
|
protected final Type componentType;
|
||||||
|
|
||||||
private final Type componentType;
|
|
||||||
|
|
||||||
protected final Class componentClass;
|
protected final Class componentClass;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ package org.redkale.convert;
|
|||||||
*/
|
*/
|
||||||
public abstract class Reader {
|
public abstract class Reader {
|
||||||
|
|
||||||
|
public static enum ValueType {
|
||||||
|
STRING, ARRAY, MAP;
|
||||||
|
}
|
||||||
|
|
||||||
//当前对象字段名的游标
|
//当前对象字段名的游标
|
||||||
protected int fieldIndex;
|
protected int fieldIndex;
|
||||||
|
|
||||||
@@ -73,6 +77,13 @@ public abstract class Reader {
|
|||||||
*/
|
*/
|
||||||
public abstract void readBlank();
|
public abstract void readBlank();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取下个值的类型
|
||||||
|
*
|
||||||
|
* @return ValueType
|
||||||
|
*/
|
||||||
|
public abstract ValueType readType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
import java.util.function.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化的数据输出流
|
* 序列化的数据输出流
|
||||||
@@ -23,6 +25,12 @@ public abstract class Writer {
|
|||||||
//convertTo时是否以指定Type的ObjectEncoder进行处理
|
//convertTo时是否以指定Type的ObjectEncoder进行处理
|
||||||
protected Type specify;
|
protected Type specify;
|
||||||
|
|
||||||
|
//对某个字段值进行动态处理
|
||||||
|
protected BiFunction<Attribute, Object, Object> objFieldFunc;
|
||||||
|
|
||||||
|
//对某个对象进行动态扩展字段值处理
|
||||||
|
protected Function<Object, ConvertField[]> objExtFunc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置specify
|
* 设置specify
|
||||||
*
|
*
|
||||||
@@ -38,6 +46,11 @@ public abstract class Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean recycle() {
|
||||||
|
this.objFieldFunc = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回specify
|
* 返回specify
|
||||||
*
|
*
|
||||||
@@ -105,7 +118,12 @@ public abstract class Writer {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void writeObjectField(final EnMember member, Object obj) {
|
public void writeObjectField(final EnMember member, Object obj) {
|
||||||
Object value = member.attribute.get(obj);
|
Object value;
|
||||||
|
if (objFieldFunc == null) {
|
||||||
|
value = member.attribute.get(obj);
|
||||||
|
} else {
|
||||||
|
value = objFieldFunc.apply(member.attribute, obj);
|
||||||
|
}
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
if (tiny()) {
|
if (tiny()) {
|
||||||
if (member.istring) {
|
if (member.istring) {
|
||||||
@@ -114,11 +132,49 @@ public abstract class Writer {
|
|||||||
if (!((Boolean) value)) return;
|
if (!((Boolean) value)) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.writeFieldName(member);
|
Attribute attr = member.getAttribute();
|
||||||
|
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
|
||||||
member.encoder.convertTo(this, value);
|
member.encoder.convertTo(this, value);
|
||||||
this.comma = true;
|
this.comma = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出一个对象的某个扩展字段
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param fieldName 字段名称
|
||||||
|
* @param fieldType 字段类型
|
||||||
|
* @param fieldPos 字段顺序
|
||||||
|
* @param anyEncoder Encoder
|
||||||
|
* @param value 写入的字段对象
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) {
|
||||||
|
if (value == null) return;
|
||||||
|
if (fieldType == null) fieldType = value.getClass();
|
||||||
|
if (tiny() && fieldType instanceof Class) {
|
||||||
|
Class clazz = (Class) fieldType;
|
||||||
|
if (CharSequence.class.isAssignableFrom(clazz)) {
|
||||||
|
if (((CharSequence) value).length() == 0) return;
|
||||||
|
} else if (clazz == boolean.class || clazz == Boolean.class) {
|
||||||
|
if (!((Boolean) value)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.writeFieldName(fieldName, fieldType, fieldPos);
|
||||||
|
anyEncoder.convertTo(this, value);
|
||||||
|
this.comma = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出一个字段名
|
||||||
|
*
|
||||||
|
* @param member 字段
|
||||||
|
*/
|
||||||
|
public final void writeFieldName(final EnMember member) {
|
||||||
|
Attribute attr = member.getAttribute();
|
||||||
|
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出一个对象后的操作
|
* 输出一个对象后的操作
|
||||||
*
|
*
|
||||||
@@ -129,9 +185,9 @@ public abstract class Writer {
|
|||||||
/**
|
/**
|
||||||
* 输出一个数组前的操作
|
* 输出一个数组前的操作
|
||||||
*
|
*
|
||||||
* @param size 数组长度
|
* @param size 数组长度
|
||||||
* @param componentEncoder Encodeable
|
* @param componentEncoder Encodeable
|
||||||
* @param obj 对象
|
* @param obj 对象, 不一定是数组、Collection对象,也可能是伪Collection对象
|
||||||
*
|
*
|
||||||
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
||||||
*/
|
*/
|
||||||
@@ -155,7 +211,7 @@ public abstract class Writer {
|
|||||||
* @param size map大小
|
* @param size map大小
|
||||||
* @param keyEncoder Encodeable
|
* @param keyEncoder Encodeable
|
||||||
* @param valueEncoder Encodeable
|
* @param valueEncoder Encodeable
|
||||||
* @param obj 对象
|
* @param obj 对象, 不一定是Map对象,也可能是伪Map对象
|
||||||
*
|
*
|
||||||
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
* @return 返回-1表示还没有写入对象内容,大于-1表示已写入对象内容,返回对象内容大小
|
||||||
*/
|
*/
|
||||||
@@ -176,9 +232,11 @@ public abstract class Writer {
|
|||||||
/**
|
/**
|
||||||
* 输出一个字段名
|
* 输出一个字段名
|
||||||
*
|
*
|
||||||
* @param member 字段的EnMember对象
|
* @param fieldName 字段名称
|
||||||
|
* @param fieldType 字段类型
|
||||||
|
* @param fieldPos 字段顺序
|
||||||
*/
|
*/
|
||||||
public abstract void writeFieldName(EnMember member);
|
public abstract void writeFieldName(String fieldName, Type fieldType, int fieldPos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写入一个boolean值
|
* 写入一个boolean值
|
||||||
@@ -256,4 +314,11 @@ public abstract class Writer {
|
|||||||
* @param value String值
|
* @param value String值
|
||||||
*/
|
*/
|
||||||
public abstract void writeString(String value);
|
public abstract void writeString(String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入一个StringConvertWrapper值
|
||||||
|
*
|
||||||
|
* @param value StringConvertWrapper值
|
||||||
|
*/
|
||||||
|
public abstract void writeWrapper(StringWrapper value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public class BsonByteBufferWriter extends BsonWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
this.buffers = null;
|
this.buffers = null;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import org.redkale.util.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||||
|
|
||||||
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
||||||
|
|
||||||
@@ -59,6 +59,21 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
return BsonFactory.root().getConvert();
|
return BsonFactory.root().getConvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||||
|
return newConvert(fieldFunc, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||||
|
return new BsonConvert(getFactory(), tiny) {
|
||||||
|
@Override
|
||||||
|
protected <S extends BsonWriter> S configWrite(S writer) {
|
||||||
|
return fieldFunc(writer, fieldFunc, objExtFunc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
||||||
return new BsonByteBufferReader((ConvertMask) null, buffers);
|
return new BsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
@@ -78,11 +93,11 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ writer -----------------------------------------------------------
|
//------------------------------ writer -----------------------------------------------------------
|
||||||
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
|
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
|
||||||
return new BsonByteBufferWriter(tiny, supplier);
|
return configWrite(new BsonByteBufferWriter(tiny, supplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter pollBsonWriter(final OutputStream out) {
|
public BsonWriter pollBsonWriter(final OutputStream out) {
|
||||||
return new BsonStreamWriter(tiny, out);
|
return configWrite(new BsonStreamWriter(tiny, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter pollBsonWriter() {
|
public BsonWriter pollBsonWriter() {
|
||||||
@@ -94,6 +109,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertFrom -----------------------------------------------------------
|
//------------------------------ convertFrom -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
||||||
if (bytes == null) return null;
|
if (bytes == null) return null;
|
||||||
return convertFrom(type, bytes, 0, bytes.length);
|
return convertFrom(type, bytes, 0, bytes.length);
|
||||||
@@ -161,6 +177,16 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] convertToBytes(final Object value) {
|
||||||
|
return convertTo(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] convertToBytes(final Type type, final Object value) {
|
||||||
|
return convertTo(type, value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] convertMapTo(final Object... values) {
|
public byte[] convertMapTo(final Object... values) {
|
||||||
if (values == null) return null;
|
if (values == null) return null;
|
||||||
@@ -173,33 +199,33 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
factory.loadEncoder(value.getClass()).convertTo(new BsonStreamWriter(tiny, out), value);
|
factory.loadEncoder(value.getClass()).convertTo(pollBsonWriter(out), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||||
if (type == null) return;
|
if (type == null) return;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
factory.loadEncoder(type).convertTo(new BsonStreamWriter(tiny, out), value);
|
factory.loadEncoder(type).convertTo(pollBsonWriter(out), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void convertMapTo(final OutputStream out, final Object... values) {
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(new BsonStreamWriter(tiny, out), values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(pollBsonWriter(out), values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -211,7 +237,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -223,7 +249,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -346,4 +346,9 @@ public class BsonReader extends Reader {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueType readType() {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.bson;
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.convert.ext.ByteSimpledCoder;
|
import org.redkale.convert.ext.ByteSimpledCoder;
|
||||||
@@ -43,7 +44,7 @@ public class BsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected BsonWriter(byte[] bs) {
|
protected BsonWriter(byte[] bs) {
|
||||||
this.content = bs;
|
this.content = bs == null ? new byte[0] : bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter() {
|
public BsonWriter() {
|
||||||
@@ -97,10 +98,12 @@ public class BsonWriter extends Writer {
|
|||||||
count += len;
|
count += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
if (this.content.length > defaultSize) {
|
if (this.content != null && this.content.length > defaultSize) {
|
||||||
this.content = new byte[defaultSize];
|
this.content = new byte[defaultSize];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -198,11 +201,10 @@ public class BsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeFieldName(EnMember member) {
|
public final void writeFieldName(String fieldName, Type fieldType, int fieldPos) {
|
||||||
Attribute attribute = member.getAttribute();
|
|
||||||
writeByte(BsonReader.SIGN_HASNEXT);
|
writeByte(BsonReader.SIGN_HASNEXT);
|
||||||
writeSmallString(attribute.field());
|
writeSmallString(fieldName);
|
||||||
writeByte(BsonFactory.typeEnum(attribute.type()));
|
writeByte(BsonFactory.typeEnum(fieldType));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -241,6 +243,11 @@ public class BsonWriter extends Writer {
|
|||||||
writeTo(bytes);
|
writeTo(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeWrapper(StringWrapper value) {
|
||||||
|
this.writeString(value == null ? null : value.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeNull() {
|
public final void writeNull() {
|
||||||
writeShort(Reader.SIGN_NULL);
|
writeShort(Reader.SIGN_NULL);
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ package org.redkale.convert.ext;
|
|||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CharSequence 的SimpledCoder实现
|
* CharSequence 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
* @param <R> Reader输入的子类型
|
* @param <R> Reader输入的子类型
|
||||||
* @param <W> Writer输出的子类型
|
* @param <W> Writer输出的子类型
|
||||||
@@ -28,4 +30,20 @@ public class CharSequenceSimpledCoder<R extends Reader, W extends Writer> extend
|
|||||||
public CharSequence convertFrom(R in) {
|
public CharSequence convertFrom(R in) {
|
||||||
return in.readString();
|
return in.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class StringBuilderSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringBuilder> {
|
||||||
|
|
||||||
|
public static final StringBuilderSimpledCoder instance = new StringBuilderSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, StringBuilder value) {
|
||||||
|
out.writeString(value == null ? null : value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringBuilder convertFrom(R in) {
|
||||||
|
String rs = in.readString();
|
||||||
|
return rs == null ? null : new StringBuilder(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/org/redkale/convert/ext/DurationSimpledCoder.java
Normal file
41
src/org/redkale/convert/ext/DurationSimpledCoder.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public class DurationSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Duration> {
|
||||||
|
|
||||||
|
public static final DurationSimpledCoder instance = new DurationSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, Duration value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
out.writeLong(value.toNanos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Duration convertFrom(R in) {
|
||||||
|
String value = in.readSmallString();
|
||||||
|
if (value == null) return null;
|
||||||
|
return Duration.ofNanos(Long.parseLong(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ import org.redkale.convert.*;
|
|||||||
*/
|
*/
|
||||||
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
||||||
|
|
||||||
public static final PatternSimpledCoder instance = new PatternSimpledCoder();
|
public static final FileSimpledCoder instance = new FileSimpledCoder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void convertTo(W out, File value) {
|
public void convertTo(W out, File value) {
|
||||||
|
|||||||
35
src/org/redkale/convert/ext/StringWrapperSimpledCoder.java
Normal file
35
src/org/redkale/convert/ext/StringWrapperSimpledCoder.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.util.StringWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public final class StringWrapperSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringWrapper> {
|
||||||
|
|
||||||
|
public static final StringWrapperSimpledCoder instance = new StringWrapperSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, StringWrapper value) {
|
||||||
|
out.writeWrapper(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringWrapper convertFrom(R in) {
|
||||||
|
return new StringWrapper(in.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -69,6 +69,10 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected final char nextChar() {
|
protected final char nextChar() {
|
||||||
|
return nextChar(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final char nextChar(StringBuilder sb) {
|
||||||
if (currentChar != 0) {
|
if (currentChar != 0) {
|
||||||
char ch = currentChar;
|
char ch = currentChar;
|
||||||
this.currentChar = 0;
|
this.currentChar = 0;
|
||||||
@@ -78,14 +82,18 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
int remain = this.currentBuffer.remaining();
|
int remain = this.currentBuffer.remaining();
|
||||||
if (remain == 0 && this.currentIndex + 1 >= this.buffers.length) return 0;
|
if (remain == 0 && this.currentIndex + 1 >= this.buffers.length) return 0;
|
||||||
}
|
}
|
||||||
byte b1 = nextByte();
|
byte b = nextByte();
|
||||||
if (b1 >= 0) {// 1 byte, 7 bits: 0xxxxxxx
|
if (b >= 0) {// 1 byte, 7 bits: 0xxxxxxx
|
||||||
return (char) b1;
|
return (char) b;
|
||||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
} else if ((b >> 5) == -2 && (b & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
||||||
return (char) (((b1 << 6) ^ nextByte()) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80)));
|
return (char) (((b << 6) ^ nextByte()) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80)));
|
||||||
} else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
} else if ((b >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
return (char) ((b1 << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80))));
|
return (char) ((b << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80))));
|
||||||
} else { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
} else if ((b >> 3) == -2) {// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
int uc = ((b << 18) ^ (nextByte() << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xF0 << 18) ^ ((byte) 0x80 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80))));
|
||||||
|
if (sb != null) sb.append(Character.highSurrogate(uc));
|
||||||
|
return Character.lowSurrogate(uc);
|
||||||
|
} else {
|
||||||
throw new RuntimeException(new UnmappableCharacterException(4));
|
throw new RuntimeException(new UnmappableCharacterException(4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,9 +216,9 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
if (ch == '"' || ch == '\'') {
|
if (ch == '"' || ch == '\'') {
|
||||||
final char quote = ch;
|
final char quote = ch;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ch = nextChar();
|
ch = nextChar(sb);
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
char c = nextChar();
|
char c = nextChar(sb);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '"':
|
case '"':
|
||||||
case '\'':
|
case '\'':
|
||||||
@@ -249,9 +257,9 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
} else {
|
} else {
|
||||||
sb.append(ch);
|
sb.append(ch);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ch = nextChar();
|
ch = nextChar(sb);
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
char c = nextChar();
|
char c = nextChar(sb);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '"':
|
case '"':
|
||||||
case '\'':
|
case '\'':
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
this.charset = null;
|
this.charset = null;
|
||||||
@@ -114,7 +115,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
int byteLength = quote ? 2 : 0;
|
int byteLength = quote ? 2 : 0;
|
||||||
ByteBuffer bb = null;
|
ByteBuffer bb = null;
|
||||||
if (charset == null) {
|
if (charset == null) {
|
||||||
byteLength += encodeUTF8Length(chs, start, len);
|
byteLength += Utility.encodeUTF8Length(chs, start, len);
|
||||||
} else {
|
} else {
|
||||||
bb = charset.encode(CharBuffer.wrap(chs, start, len));
|
bb = charset.encode(CharBuffer.wrap(chs, start, len));
|
||||||
byteLength += bb.remaining();
|
byteLength += bb.remaining();
|
||||||
@@ -133,6 +134,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
} else if (c < 0x800) {
|
} else if (c < 0x800) {
|
||||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (Character.isSurrogate(c)) { //连取两个
|
||||||
|
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||||
|
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||||
|
i++;
|
||||||
} else {
|
} else {
|
||||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
@@ -154,7 +162,34 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
if (charset == null) { //UTF-8
|
if (charset == null) { //UTF-8
|
||||||
final int limit = start + len;
|
final int limit = start + len;
|
||||||
for (int i = start; i < limit; i++) {
|
for (int i = start; i < limit; i++) {
|
||||||
buffer = putUTF8Char(buffer, chs[i]);
|
char c = chs[i];
|
||||||
|
if (c < 0x80) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) c);
|
||||||
|
} else if (c < 0x800) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (Character.isSurrogate(c)) { //连取两个
|
||||||
|
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (bb.hasRemaining()) {
|
while (bb.hasRemaining()) {
|
||||||
@@ -168,50 +203,18 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ByteBuffer putUTF8Char(ByteBuffer buffer, char c) {
|
|
||||||
if (c < 0x80) {
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) c);
|
|
||||||
} else if (c < 0x800) {
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
|
||||||
} else {
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
|
||||||
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ByteBuffer nextByteBuffer() {
|
private ByteBuffer nextByteBuffer() {
|
||||||
this.buffers[this.index].flip();
|
this.buffers[this.index].flip();
|
||||||
return this.buffers[++this.index];
|
return this.buffers[++this.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int encodeUTF8Length(final char[] text, final int start, final int len) {
|
|
||||||
char c;
|
|
||||||
int size = 0;
|
|
||||||
final char[] chars = text;
|
|
||||||
final int limit = start + len;
|
|
||||||
for (int i = start; i < limit; i++) {
|
|
||||||
c = chars[i];
|
|
||||||
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) {
|
protected static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) {
|
||||||
char c;
|
char c;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
final char[] chars = text;
|
final char[] chs = text;
|
||||||
final int limit = start + len;
|
final int limit = start + len;
|
||||||
for (int i = start; i < limit; i++) {
|
for (int i = start; i < limit; i++) {
|
||||||
c = chars[i];
|
c = chs[i];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\n': size += 2;
|
case '\n': size += 2;
|
||||||
break;
|
break;
|
||||||
@@ -224,7 +227,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
case '"': size += 2;
|
case '"': size += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
|
size += (c < 0x80 ? 1 : (c < 0x800 || Character.isSurrogate(c) ? 2 : 3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,19 +241,39 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
* @param value String值
|
* @param value String值
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(final boolean quote, final String value) {
|
public void writeLatin1To(final boolean quote, final String value) {
|
||||||
char[] chs = Utility.charArray(value);
|
byte[] bs = Utility.byteArray(value);
|
||||||
writeTo(-1, quote, chs, 0, chs.length);
|
int expandsize = expand(bs.length + (quote ? 2 : 0));
|
||||||
|
if (expandsize == 0) {// 只需要一个buffer
|
||||||
|
final ByteBuffer buffer = this.buffers[index];
|
||||||
|
if (quote) buffer.put((byte) '"');
|
||||||
|
buffer.put(bs);
|
||||||
|
if (quote) buffer.put((byte) '"');
|
||||||
|
} else {
|
||||||
|
ByteBuffer buffer = this.buffers[index];
|
||||||
|
if (quote) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) '"');
|
||||||
|
}
|
||||||
|
for (byte b : bs) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put(b);
|
||||||
|
}
|
||||||
|
if (quote) {
|
||||||
|
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
|
||||||
|
buffer.put((byte) '"');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeInt(int value) {
|
public void writeInt(int value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeLong(long value) {
|
public void writeLong(long value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -288,7 +311,8 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
if (expandsize == 0) { // 只需要一个buffer
|
if (expandsize == 0) { // 只需要一个buffer
|
||||||
final ByteBuffer buffer = this.buffers[index];
|
final ByteBuffer buffer = this.buffers[index];
|
||||||
buffer.put((byte) '"');
|
buffer.put((byte) '"');
|
||||||
for (char c : chs) {
|
for (int i = 0; i < chs.length; i++) {
|
||||||
|
char c = chs[i];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\n': buffer.put((byte) '\\').put((byte) 'n');
|
case '\n': buffer.put((byte) '\\').put((byte) 'n');
|
||||||
break;
|
break;
|
||||||
@@ -306,6 +330,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
} else if (c < 0x800) {
|
} else if (c < 0x800) {
|
||||||
buffer.put((byte) (0xc0 | (c >> 6)));
|
buffer.put((byte) (0xc0 | (c >> 6)));
|
||||||
buffer.put((byte) (0x80 | (c & 0x3f)));
|
buffer.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (Character.isSurrogate(c)) { //连取两个
|
||||||
|
int uc = Character.toCodePoint(c, chs[i + 1]);
|
||||||
|
buffer.put((byte) (0xf0 | ((uc >> 18))));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||||
|
buffer.put((byte) (0x80 | (uc & 0x3f)));
|
||||||
|
i++;
|
||||||
} else {
|
} else {
|
||||||
buffer.put((byte) (0xe0 | ((c >> 12))));
|
buffer.put((byte) (0xe0 | ((c >> 12))));
|
||||||
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.nio.*;
|
|||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.service.RetResult;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,11 +22,14 @@ import org.redkale.util.*;
|
|||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||||
|
|
||||||
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() {
|
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
|
|
||||||
|
public static final Type TYPE_RETRESULT_STRING = new TypeToken<RetResult<String>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
private static final ObjectPool<JsonReader> readerPool = JsonReader.createPool(Integer.getInteger("convert.json.pool.size", 16));
|
private static final ObjectPool<JsonReader> readerPool = JsonReader.createPool(Integer.getInteger("convert.json.pool.size", 16));
|
||||||
|
|
||||||
private static final ObjectPool<JsonWriter> writerPool = JsonWriter.createPool(Integer.getInteger("convert.json.pool.size", 16));
|
private static final ObjectPool<JsonWriter> writerPool = JsonWriter.createPool(Integer.getInteger("convert.json.pool.size", 16));
|
||||||
@@ -46,6 +50,21 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
return JsonFactory.root().getConvert();
|
return JsonFactory.root().getConvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||||
|
return newConvert(fieldFunc, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||||
|
return new JsonConvert(getFactory(), tiny) {
|
||||||
|
@Override
|
||||||
|
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||||
|
return fieldFunc(writer, fieldFunc, objExtFunc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
||||||
return new JsonByteBufferReader((ConvertMask) null, buffers);
|
return new JsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
@@ -65,19 +84,19 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ writer -----------------------------------------------------------
|
//------------------------------ writer -----------------------------------------------------------
|
||||||
public JsonByteBufferWriter pollJsonWriter(final Supplier<ByteBuffer> supplier) {
|
public JsonByteBufferWriter pollJsonWriter(final Supplier<ByteBuffer> supplier) {
|
||||||
return new JsonByteBufferWriter(tiny, supplier);
|
return configWrite(new JsonByteBufferWriter(tiny, supplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter(final OutputStream out) {
|
public JsonWriter pollJsonWriter(final OutputStream out) {
|
||||||
return new JsonStreamWriter(tiny, out);
|
return configWrite(new JsonStreamWriter(tiny, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter(final Charset charset, final OutputStream out) {
|
public JsonWriter pollJsonWriter(final Charset charset, final OutputStream out) {
|
||||||
return new JsonStreamWriter(tiny, charset, out);
|
return configWrite(new JsonStreamWriter(tiny, charset, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter() {
|
public JsonWriter pollJsonWriter() {
|
||||||
return writerPool.get().tiny(tiny);
|
return configWrite(writerPool.get().tiny(tiny));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerJsonWriter(final JsonWriter writer) {
|
public void offerJsonWriter(final JsonWriter writer) {
|
||||||
@@ -85,6 +104,12 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertFrom -----------------------------------------------------------
|
//------------------------------ convertFrom -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
|
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
||||||
|
if (bytes == null) return null;
|
||||||
|
return convertFrom(type, new String(bytes, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
public <T> T convertFrom(final Type type, final String text) {
|
public <T> T convertFrom(final Type type, final String text) {
|
||||||
if (text == null) return null;
|
if (text == null) return null;
|
||||||
return convertFrom(type, Utility.charArray(text));
|
return convertFrom(type, Utility.charArray(text));
|
||||||
@@ -128,6 +153,52 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final String text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
return (V) convertFrom(Utility.charArray(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final char[] text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
return (V) convertFrom(text, 0, text.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final char[] text, final int start, final int len) {
|
||||||
|
if (text == null) return null;
|
||||||
|
final JsonReader in = readerPool.get();
|
||||||
|
in.setText(text, start, len);
|
||||||
|
Object rs = new AnyDecoder(factory).convertFrom(in);
|
||||||
|
readerPool.accept(in);
|
||||||
|
return (V) rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final InputStream in) {
|
||||||
|
if (in == null) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonStreamReader(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final ByteBuffer... buffers) {
|
||||||
|
if (buffers == null || buffers.length == 0) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final ConvertMask mask, final ByteBuffer... buffers) {
|
||||||
|
if (buffers == null || buffers.length == 0) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader(mask, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回非null的值是由String、ArrayList、HashMap任意组合的对象
|
||||||
|
public <V> V convertFrom(final JsonReader reader) {
|
||||||
|
if (reader == null) return null;
|
||||||
|
return (V) new AnyDecoder(factory).convertFrom(reader);
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ convertTo -----------------------------------------------------------
|
//------------------------------ convertTo -----------------------------------------------------------
|
||||||
@Override
|
@Override
|
||||||
public String convertTo(final Object value) {
|
public String convertTo(final Object value) {
|
||||||
@@ -139,7 +210,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
public String convertTo(final Type type, final Object value) {
|
public String convertTo(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
if (value == null) return "null";
|
if (value == null) return "null";
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
String result = writer.toString();
|
String result = writer.toString();
|
||||||
@@ -147,10 +218,29 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] convertToBytes(final Object value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
String result = convertTo(value.getClass(), value);
|
||||||
|
return result == null ? null : result.getBytes(StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] convertToBytes(final Type type, final Object value) {
|
||||||
|
if (type == null) return null;
|
||||||
|
if (value == null) return null;
|
||||||
|
final JsonWriter writer = pollJsonWriter();
|
||||||
|
writer.specify(type);
|
||||||
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
|
String result = writer.toString();
|
||||||
|
writerPool.accept(writer);
|
||||||
|
return result == null ? null : result.getBytes(StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String convertMapTo(final Object... values) {
|
public String convertMapTo(final Object... values) {
|
||||||
if (values == null) return "null";
|
if (values == null) return "null";
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
String result = writer.toString();
|
String result = writer.toString();
|
||||||
writerPool.accept(writer);
|
writerPool.accept(writer);
|
||||||
@@ -159,7 +249,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
convertTo(out, value.getClass(), value);
|
convertTo(out, value.getClass(), value);
|
||||||
}
|
}
|
||||||
@@ -168,9 +258,9 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||||
if (type == null) return;
|
if (type == null) return;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
byte[] bs = writer.toBytes();
|
byte[] bs = writer.toBytes();
|
||||||
@@ -185,9 +275,9 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public void convertMapTo(final OutputStream out, final Object... values) {
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
byte[] bs = writer.toBytes();
|
byte[] bs = writer.toBytes();
|
||||||
writerPool.accept(writer);
|
writerPool.accept(writer);
|
||||||
@@ -202,7 +292,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -214,7 +304,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -227,7 +317,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -269,14 +359,14 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public JsonWriter convertToWriter(final Type type, final Object value) {
|
public JsonWriter convertToWriter(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
return writer;
|
return writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter convertMapToWriter(final Object... values) {
|
public JsonWriter convertMapToWriter(final Object... values) {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
return writer;
|
return writer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,7 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
|||||||
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
|
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
|
||||||
|
|
||||||
static {
|
static {
|
||||||
instance.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
|
||||||
instance.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
|
||||||
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
|
||||||
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
|
||||||
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
||||||
|
|
||||||
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
|
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
|
||||||
@@ -38,6 +35,12 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
private JsonFactory(JsonFactory parent, boolean tiny) {
|
private JsonFactory(JsonFactory parent, boolean tiny) {
|
||||||
super(parent, tiny);
|
super(parent, tiny);
|
||||||
|
if (parent == null) {
|
||||||
|
this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
||||||
|
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
||||||
|
this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
||||||
|
this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -158,6 +158,21 @@ public class JsonReader extends Reader {
|
|||||||
this.position--;
|
this.position--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ValueType readType() {
|
||||||
|
char ch = nextGoodChar();
|
||||||
|
if (ch == '{') {
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.MAP;
|
||||||
|
}
|
||||||
|
if (ch == '[') {
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.ARRAY;
|
||||||
|
}
|
||||||
|
backChar(ch);
|
||||||
|
return ValueType.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断下一个非空白字符是否为{
|
* 判断下一个非空白字符是否为{
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -87,19 +87,19 @@ class JsonStreamWriter extends JsonByteBufferWriter {
|
|||||||
* @param value String值
|
* @param value String值
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(final boolean quote, final String value) {
|
public void writeLatin1To(final boolean quote, final String value) {
|
||||||
char[] chs = Utility.charArray(value);
|
char[] chs = Utility.charArray(value);
|
||||||
writeTo(quote, chs, 0, chs.length);
|
writeTo(quote, chs, 0, chs.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeInt(int value) {
|
public void writeInt(int value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeLong(long value) {
|
public void writeLong(long value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.json;
|
package org.redkale.convert.json;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
@@ -88,7 +89,7 @@ public class JsonWriter extends Writer {
|
|||||||
* @param quote 是否加双引号
|
* @param quote 是否加双引号
|
||||||
* @param value 非null且不含需要转义的字符的String值
|
* @param value 非null且不含需要转义的字符的String值
|
||||||
*/
|
*/
|
||||||
public void writeTo(final boolean quote, final String value) {
|
public void writeLatin1To(final boolean quote, final String value) {
|
||||||
int len = value.length();
|
int len = value.length();
|
||||||
expand(len + (quote ? 2 : 0));
|
expand(len + (quote ? 2 : 0));
|
||||||
if (quote) content[count++] = '"';
|
if (quote) content[count++] = '"';
|
||||||
@@ -97,10 +98,12 @@ public class JsonWriter extends Writer {
|
|||||||
if (quote) content[count++] = '"';
|
if (quote) content[count++] = '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
if (this.content.length > defaultSize) {
|
if (this.content != null && this.content.length > defaultSize) {
|
||||||
this.content = new char[defaultSize];
|
this.content = new char[defaultSize];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -157,15 +160,15 @@ public class JsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeFieldName(EnMember member) {
|
public final void writeFieldName(String fieldName, Type fieldType, int fieldPos) {
|
||||||
if (this.comma) writeTo(',');
|
if (this.comma) writeTo(',');
|
||||||
writeTo(true, member.getAttribute().field());
|
writeLatin1To(true, fieldName);
|
||||||
writeTo(':');
|
writeTo(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeSmallString(String value) {
|
public final void writeSmallString(String value) {
|
||||||
writeTo(true, value);
|
writeLatin1To(true, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -311,12 +314,17 @@ public class JsonWriter extends Writer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeFloat(float value) {
|
public final void writeFloat(float value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeDouble(double value) {
|
public final void writeDouble(double value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeLatin1To(false, String.valueOf(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void writeWrapper(StringWrapper value) {
|
||||||
|
writeLatin1To(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
238
src/org/redkale/mq/HttpMessageClient.java
Normal file
238
src/org/redkale/mq/HttpMessageClient.java
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.redkale.convert.ConvertType;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不依赖MessageRecord则可兼容RPC方式
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class HttpMessageClient extends MessageClient {
|
||||||
|
|
||||||
|
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
|
|
||||||
|
protected HttpMessageClient(MessageAgent messageAgent) {
|
||||||
|
super(messageAgent);
|
||||||
|
if (messageAgent != null) { // //RPC方式下无messageAgent
|
||||||
|
this.respTopic = messageAgent.generateHttpRespTopic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: http.req.user
|
||||||
|
public String generateHttpReqTopic(String module) {
|
||||||
|
return MessageAgent.generateHttpReqTopic(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: http.req.user-n10
|
||||||
|
public String generateHttpReqTopic(String module, String resname) {
|
||||||
|
return MessageAgent.generateHttpReqTopic(module, resname);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateHttpReqTopic(HttpSimpleRequest request, String path) {
|
||||||
|
String module = request.getRequestURI();
|
||||||
|
if (path != null && !path.isEmpty() && module.startsWith(path)) module = module.substring(path.length());
|
||||||
|
module = module.substring(1); //去掉/
|
||||||
|
module = module.substring(0, module.indexOf('/'));
|
||||||
|
Map<String, String> headers = request.getHeaders();
|
||||||
|
String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, "");
|
||||||
|
return MessageAgent.generateHttpReqTopic(module, resname);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(HttpSimpleRequest request) {
|
||||||
|
produceMessage(generateHttpReqTopic(request, null), ConvertType.JSON, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
produceMessage(generateHttpReqTopic(request, null), ConvertType.JSON, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(int userid, HttpSimpleRequest request) {
|
||||||
|
produceMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
produceMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
produceMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, groupid, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(String topic, HttpSimpleRequest request) {
|
||||||
|
produceMessage(topic, ConvertType.JSON, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(String topic, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
produceMessage(topic, ConvertType.JSON, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(String topic, ConvertType convertType, HttpSimpleRequest request) {
|
||||||
|
produceMessage(topic, convertType, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(String topic, ConvertType convertType, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
produceMessage(topic, convertType, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(String topic, int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
produceMessage(topic, ConvertType.JSON, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(String topic, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
produceMessage(topic, ConvertType.JSON, userid, groupid, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void produceMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
produceMessage(topic, convertType, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(HttpSimpleRequest request) {
|
||||||
|
broadcastMessage(generateHttpReqTopic(request, null), ConvertType.JSON, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
broadcastMessage(generateHttpReqTopic(request, null), ConvertType.JSON, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(int userid, HttpSimpleRequest request) {
|
||||||
|
broadcastMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
broadcastMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
broadcastMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, groupid, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(String topic, HttpSimpleRequest request) {
|
||||||
|
broadcastMessage(topic, ConvertType.JSON, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(String topic, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
broadcastMessage(topic, ConvertType.JSON, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(String topic, ConvertType convertType, HttpSimpleRequest request) {
|
||||||
|
broadcastMessage(topic, convertType, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(String topic, ConvertType convertType, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
broadcastMessage(topic, convertType, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(String topic, int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
broadcastMessage(topic, ConvertType.JSON, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(String topic, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
broadcastMessage(topic, ConvertType.JSON, userid, groupid, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void broadcastMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
broadcastMessage(topic, convertType, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final <T> CompletableFuture<T> sendMessage(HttpSimpleRequest request, Type type) {
|
||||||
|
return sendMessage(generateHttpReqTopic(request, null), ConvertType.JSON, 0, null, request, null).thenApply((HttpResult<byte[]> httbs) -> {
|
||||||
|
if (httbs == null || httbs.getResult() == null) return null;
|
||||||
|
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public final <T> CompletableFuture<T> sendMessage(int userid, HttpSimpleRequest request, Type type) {
|
||||||
|
return sendMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, null, request, null).thenApply((HttpResult<byte[]> httbs) -> {
|
||||||
|
if (httbs == null || httbs.getResult() == null) return null;
|
||||||
|
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(HttpSimpleRequest request) {
|
||||||
|
return sendMessage(generateHttpReqTopic(request, null), ConvertType.JSON, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
return sendMessage(generateHttpReqTopic(request, null), ConvertType.JSON, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(int userid, HttpSimpleRequest request) {
|
||||||
|
return sendMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
return sendMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
return sendMessage(generateHttpReqTopic(request, null), ConvertType.JSON, userid, groupid, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, HttpSimpleRequest request) {
|
||||||
|
return sendMessage(topic, ConvertType.JSON, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
return sendMessage(topic, ConvertType.JSON, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, ConvertType convertType, HttpSimpleRequest request) {
|
||||||
|
return sendMessage(topic, convertType, 0, null, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, ConvertType convertType, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
return sendMessage(topic, convertType, 0, null, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
return sendMessage(topic, ConvertType.JSON, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
return sendMessage(topic, ConvertType.JSON, userid, groupid, request, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request) {
|
||||||
|
return sendMessage(topic, convertType, userid, groupid, request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
MessageRecord message = new MessageRecord(convertType, topic, null, HttpSimpleRequestCoder.getInstance().encode(request));
|
||||||
|
message.userid(userid).groupid(groupid);
|
||||||
|
return sendMessage(message, true, counter).thenApply(r -> r.decodeContent(HttpResultCoder.getInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void broadcastMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
MessageRecord message = new MessageRecord(convertType, topic, null, HttpSimpleRequestCoder.getInstance().encode(request));
|
||||||
|
message.userid(userid).groupid(groupid);
|
||||||
|
sendMessage(message, false, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void produceMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
MessageRecord message = new MessageRecord(convertType, topic, null, HttpSimpleRequestCoder.getInstance().encode(request));
|
||||||
|
message.userid(userid).groupid(groupid);
|
||||||
|
sendMessage(message, false, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MessageProducers getProducer() {
|
||||||
|
return messageAgent.getHttpProducer();
|
||||||
|
}
|
||||||
|
}
|
||||||
150
src/org/redkale/mq/HttpMessageClusterClient.java
Normal file
150
src/org/redkale/mq/HttpMessageClusterClient.java
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.redkale.cluster.ClusterAgent;
|
||||||
|
import org.redkale.convert.ConvertType;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 没有配置MQ的情况下依赖ClusterAgent实现的默认HttpMessageClient实例
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class HttpMessageClusterClient extends HttpMessageClient {
|
||||||
|
|
||||||
|
//jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET
|
||||||
|
private static final Set<String> DISALLOWED_HEADERS_SET = Set.of("connection", "content-length",
|
||||||
|
"date", "expect", "from", "host", "origin",
|
||||||
|
"referer", "upgrade", "via", "warning");
|
||||||
|
|
||||||
|
protected ClusterAgent clusterAgent;
|
||||||
|
|
||||||
|
protected java.net.http.HttpClient httpClient;
|
||||||
|
|
||||||
|
public HttpMessageClusterClient(ClusterAgent clusterAgent) {
|
||||||
|
super(null);
|
||||||
|
Objects.requireNonNull(clusterAgent);
|
||||||
|
this.clusterAgent = clusterAgent;
|
||||||
|
this.httpClient = java.net.http.HttpClient.newHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
return httpAsync(userid, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void produceMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
httpAsync(userid, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void broadcastMessage(String topic, ConvertType convertType, int userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
|
||||||
|
mqtpAsync(userid, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<HttpResult<byte[]>> mqtpAsync(int userid, HttpSimpleRequest req) {
|
||||||
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
String module = req.getRequestURI();
|
||||||
|
module = module.substring(1); //去掉/
|
||||||
|
module = module.substring(0, module.indexOf('/'));
|
||||||
|
Map<String, String> headers = req.getHeaders();
|
||||||
|
String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, "");
|
||||||
|
return clusterAgent.queryMqtpAddress("mqtp", module, resname).thenCompose(addrmap -> {
|
||||||
|
if (addrmap == null || addrmap.isEmpty()) return new HttpResult().status(404).toAnyFuture();
|
||||||
|
java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().timeout(Duration.ofMillis(30000));
|
||||||
|
if (req.isRpc()) builder.header(Rest.REST_HEADER_RPC_NAME, "true");
|
||||||
|
if (userid != 0) builder.header(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid);
|
||||||
|
if (headers != null) headers.forEach((n, v) -> {
|
||||||
|
if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) builder.header(n, v);
|
||||||
|
});
|
||||||
|
builder.header("Content-Type", "x-www-form-urlencoded");
|
||||||
|
String paramstr = req.getParametersToString();
|
||||||
|
if (paramstr != null) builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(paramstr));
|
||||||
|
List<CompletableFuture> futures = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Collection<InetSocketAddress>> en : addrmap.entrySet()) {
|
||||||
|
String realmodule = en.getKey();
|
||||||
|
Collection<InetSocketAddress> addrs = en.getValue();
|
||||||
|
if (addrs == null || addrs.isEmpty()) continue;
|
||||||
|
String suburi = req.getRequestURI();
|
||||||
|
suburi = suburi.substring(1); //跳过 /
|
||||||
|
suburi = "/" + realmodule + suburi.substring(suburi.indexOf('/'));
|
||||||
|
futures.add(forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + suburi, builder, addrs.iterator()));
|
||||||
|
}
|
||||||
|
if (futures.isEmpty()) return CompletableFuture.completedFuture(null);
|
||||||
|
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(v -> null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<HttpResult<byte[]>> httpAsync(int userid, HttpSimpleRequest req) {
|
||||||
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
String module = req.getRequestURI();
|
||||||
|
module = module.substring(1); //去掉/
|
||||||
|
module = module.substring(0, module.indexOf('/'));
|
||||||
|
Map<String, String> headers = req.getHeaders();
|
||||||
|
String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, "");
|
||||||
|
return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> {
|
||||||
|
if (addrs == null || addrs.isEmpty()) return new HttpResult().status(404).toAnyFuture();
|
||||||
|
java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().timeout(Duration.ofMillis(30000));
|
||||||
|
if (req.isRpc()) builder.header(Rest.REST_HEADER_RPC_NAME, "true");
|
||||||
|
if (userid != 0) builder.header(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid);
|
||||||
|
if (headers != null) headers.forEach((n, v) -> {
|
||||||
|
if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) builder.header(n, v);
|
||||||
|
});
|
||||||
|
builder.header("Content-Type", "x-www-form-urlencoded");
|
||||||
|
String paramstr = req.getParametersToString();
|
||||||
|
if (paramstr != null) builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(paramstr));
|
||||||
|
return forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + req.getRequestURI(), builder, addrs.iterator());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<HttpResult<byte[]>> forEachCollectionFuture(boolean finest, int userid, HttpSimpleRequest req, String requesturi, java.net.http.HttpRequest.Builder builder, Iterator<InetSocketAddress> it) {
|
||||||
|
if (!it.hasNext()) return CompletableFuture.completedFuture(null);
|
||||||
|
InetSocketAddress addr = it.next();
|
||||||
|
String url = "http://" + addr.getHostString() + ":" + addr.getPort() + requesturi;
|
||||||
|
return httpClient.sendAsync(builder.copy().uri(URI.create(url)).build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()).thenCompose(resp -> {
|
||||||
|
if (resp.statusCode() != 200) return forEachCollectionFuture(finest, userid, req, requesturi, builder, it);
|
||||||
|
HttpResult rs = new HttpResult();
|
||||||
|
java.net.http.HttpHeaders hs = resp.headers();
|
||||||
|
if (hs != null) {
|
||||||
|
Map<String, List<String>> hm = hs.map();
|
||||||
|
if (hm != null) {
|
||||||
|
for (Map.Entry<String, List<String>> en : hm.entrySet()) {
|
||||||
|
if ("date".equals(en.getKey()) || "content-type".equals(en.getKey())
|
||||||
|
|| "server".equals(en.getKey()) || "connection".equals(en.getKey())) continue;
|
||||||
|
List<String> val = en.getValue();
|
||||||
|
if (val != null && val.size() == 1) {
|
||||||
|
rs.header(en.getKey(), val.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rs.setResult(resp.body());
|
||||||
|
if (finest) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
Map<String, String> params = req.getParams();
|
||||||
|
if (params != null && !params.isEmpty()) {
|
||||||
|
params.forEach((n, v) -> sb.append('&').append(n).append('=').append(v));
|
||||||
|
}
|
||||||
|
logger.log(Level.FINEST, url + "?userid=" + userid + sb + ", result = " + new String(resp.body(), StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
return CompletableFuture.completedFuture(rs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
126
src/org/redkale/mq/HttpMessageProcessor.java
Normal file
126
src/org/redkale/mq/HttpMessageProcessor.java
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.logging.*;
|
||||||
|
import org.redkale.boot.NodeHttpServer;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.service.Service;
|
||||||
|
import org.redkale.util.ThreadHashExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class HttpMessageProcessor implements MessageProcessor {
|
||||||
|
|
||||||
|
protected final boolean finest;
|
||||||
|
|
||||||
|
protected final Logger logger;
|
||||||
|
|
||||||
|
protected final MessageProducers producer;
|
||||||
|
|
||||||
|
protected final NodeHttpServer server;
|
||||||
|
|
||||||
|
protected final ThreadHashExecutor workExecutor;
|
||||||
|
|
||||||
|
protected final Service service;
|
||||||
|
|
||||||
|
protected final HttpServlet servlet;
|
||||||
|
|
||||||
|
protected final boolean multiconsumer;
|
||||||
|
|
||||||
|
protected final String restmodule; // 前后有/, 例如: /user/
|
||||||
|
|
||||||
|
protected final String multimodule; // 前后有/, 例如: /userstat/
|
||||||
|
|
||||||
|
protected CountDownLatch cdl;
|
||||||
|
|
||||||
|
protected final Runnable innerCallback = () -> {
|
||||||
|
if (cdl != null) cdl.countDown();
|
||||||
|
};
|
||||||
|
|
||||||
|
public HttpMessageProcessor(Logger logger, ThreadHashExecutor workExecutor, MessageProducers producer, NodeHttpServer server, Service service, HttpServlet servlet) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.finest = logger.isLoggable(Level.FINEST);
|
||||||
|
this.producer = producer;
|
||||||
|
this.server = server;
|
||||||
|
this.service = service;
|
||||||
|
this.servlet = servlet;
|
||||||
|
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
|
||||||
|
this.multiconsumer = mmc != null;
|
||||||
|
this.restmodule = "/" + Rest.getRestModule(service) + "/";
|
||||||
|
this.multimodule = mmc != null ? ("/" + mmc.module() + "/") : null;
|
||||||
|
this.workExecutor = workExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(final int size) {
|
||||||
|
if (this.workExecutor != null) this.cdl = new CountDownLatch(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(final MessageRecord message, final Runnable callback) {
|
||||||
|
if (this.workExecutor == null) {
|
||||||
|
execute(message, innerCallback);
|
||||||
|
} else {
|
||||||
|
this.workExecutor.execute(message.hash(), () -> execute(message, innerCallback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execute(final MessageRecord message, final Runnable callback) {
|
||||||
|
try {
|
||||||
|
if (finest) logger.log(Level.FINEST, "HttpMessageProcessor.process message: " + message);
|
||||||
|
if (multiconsumer) message.setResptopic(null); //不容许有响应
|
||||||
|
HttpContext context = server.getHttpServer().getContext();
|
||||||
|
HttpMessageRequest request = new HttpMessageRequest(context, message);
|
||||||
|
if (multiconsumer) {
|
||||||
|
request.setRequestURI(request.getRequestURI().replaceFirst(this.multimodule, this.restmodule));
|
||||||
|
}
|
||||||
|
HttpMessageResponse response = new HttpMessageResponse(context, request, callback, null, null, producer.getProducer(message));
|
||||||
|
servlet.execute(request, response);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
if (message.getResptopic() != null && !message.getResptopic().isEmpty()) {
|
||||||
|
HttpMessageResponse.finishHttpResult(finest, message, callback, producer.getProducer(message), message.getResptopic(), new HttpResult().status(500));
|
||||||
|
}
|
||||||
|
logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commit() {
|
||||||
|
if (this.cdl != null) {
|
||||||
|
try {
|
||||||
|
this.cdl.await(30, TimeUnit.SECONDS);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
this.cdl = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageProducers getProducer() {
|
||||||
|
return producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeHttpServer getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Service getService() {
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpServlet getServlet() {
|
||||||
|
return servlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
32
src/org/redkale/mq/HttpMessageRequest.java
Normal file
32
src/org/redkale/mq/HttpMessageRequest.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.mq;
|
||||||
|
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class HttpMessageRequest extends HttpRequest {
|
||||||
|
|
||||||
|
protected MessageRecord message;
|
||||||
|
|
||||||
|
public HttpMessageRequest(HttpContext context, MessageRecord message) {
|
||||||
|
super(context, message.decodeContent(HttpSimpleRequestCoder.getInstance()));
|
||||||
|
this.message = message;
|
||||||
|
this.currentUserid = message.getUserid();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestURI(String uri) {
|
||||||
|
this.requestURI = uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
167
src/org/redkale/mq/HttpMessageResponse.java
Normal file
167
src/org/redkale/mq/HttpMessageResponse.java
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.net.Response;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.service.RetResult;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class HttpMessageResponse extends HttpResponse {
|
||||||
|
|
||||||
|
protected MessageRecord message;
|
||||||
|
|
||||||
|
protected MessageProducer producer;
|
||||||
|
|
||||||
|
protected boolean finest;
|
||||||
|
|
||||||
|
protected Runnable callback;
|
||||||
|
|
||||||
|
public HttpMessageResponse(HttpContext context, HttpMessageRequest request, Runnable callback,
|
||||||
|
ObjectPool<Response> responsePool, HttpResponseConfig config, MessageProducer producer) {
|
||||||
|
super(context, request, responsePool, config);
|
||||||
|
this.message = request.message;
|
||||||
|
this.callback = callback;
|
||||||
|
this.producer = producer;
|
||||||
|
this.finest = producer.logger.isLoggable(Level.FINEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpMessageResponse(HttpContext context, MessageRecord message, Runnable callback, HttpResponseConfig config, MessageProducer producer) {
|
||||||
|
super(context, new HttpMessageRequest(context, message), null, config);
|
||||||
|
this.message = message;
|
||||||
|
this.callback = callback;
|
||||||
|
this.producer = producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishHttpResult(HttpResult result) {
|
||||||
|
finishHttpResult(this.finest, this.message, this.callback, this.producer, message.getResptopic(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void finishHttpResult(boolean finest, MessageRecord msg, Runnable callback, MessageProducer producer, String resptopic, HttpResult result) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
if (resptopic == null || resptopic.isEmpty()) return;
|
||||||
|
if (result.getResult() instanceof RetResult) {
|
||||||
|
RetResult ret = (RetResult) result.getResult();
|
||||||
|
//必须要塞入retcode, 开发者可以无需反序列化ret便可确定操作是否返回成功
|
||||||
|
if (!ret.isSuccess()) result.header("retcode", String.valueOf(ret.getRetcode()));
|
||||||
|
}
|
||||||
|
ConvertType format = result.convert() == null ? null : result.convert().getFactory().getConvertType();
|
||||||
|
if (finest) {
|
||||||
|
Object innerrs = result.getResult();
|
||||||
|
if (innerrs instanceof byte[]) innerrs = new String((byte[]) innerrs, StandardCharsets.UTF_8);
|
||||||
|
producer.logger.log(Level.FINEST, "HttpMessageProcessor.process seqid=" + msg.getSeqid() + ", content: " + innerrs + ", status: " + result.getStatus() + ", headers: " + result.getHeaders());
|
||||||
|
}
|
||||||
|
byte[] content = HttpResultCoder.getInstance().encode(result);
|
||||||
|
producer.apply(new MessageRecord(msg.getSeqid(), format, resptopic, null, content));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishJson(org.redkale.service.RetResult ret) {
|
||||||
|
if (message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finishHttpResult(new HttpResult(ret.clearConvert(), ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(String obj) {
|
||||||
|
if (message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finishHttpResult(new HttpResult(obj == null ? "" : obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish404() {
|
||||||
|
finish(404, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(int status, String message) {
|
||||||
|
if (finest) producer.logger.log(Level.FINEST, "HttpMessageResponse.finish status: " + status);
|
||||||
|
if (this.message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finishHttpResult(new HttpResult(message == null ? "" : message).status(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(final Convert convert, HttpResult result) {
|
||||||
|
if (message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (convert != null) result.convert(convert);
|
||||||
|
finishHttpResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(final byte[] bs) {
|
||||||
|
if (message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finishHttpResult(new HttpResult(bs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(final String contentType, final byte[] bs) {
|
||||||
|
if (message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finishHttpResult(new HttpResult(bs).contentType(contentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(boolean kill, ByteBuffer buffer) {
|
||||||
|
if (message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] bs = new byte[buffer.remaining()];
|
||||||
|
buffer.get(bs);
|
||||||
|
finishHttpResult(new HttpResult(bs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(boolean kill, ByteBuffer... buffers) {
|
||||||
|
if (message.isEmptyResptopic()) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int size = 0;
|
||||||
|
for (ByteBuffer buf : buffers) {
|
||||||
|
size += buf.remaining();
|
||||||
|
}
|
||||||
|
byte[] bs = new byte[size];
|
||||||
|
int index = 0;
|
||||||
|
for (ByteBuffer buf : buffers) {
|
||||||
|
int r = buf.remaining();
|
||||||
|
buf.get(bs, index, r);
|
||||||
|
index += r;
|
||||||
|
}
|
||||||
|
finishHttpResult(new HttpResult(bs));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
132
src/org/redkale/mq/HttpResultCoder.java
Normal file
132
src/org/redkale/mq/HttpResultCoder.java
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.net.HttpCookie;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import static org.redkale.mq.MessageCoder.*;
|
||||||
|
import org.redkale.net.http.HttpResult;
|
||||||
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpResult的MessageCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class HttpResultCoder implements MessageCoder<HttpResult> {
|
||||||
|
|
||||||
|
private static final HttpResultCoder instance = new HttpResultCoder();
|
||||||
|
|
||||||
|
public static HttpResultCoder getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encode(HttpResult data) {
|
||||||
|
if (data == null) return null;
|
||||||
|
byte[] contentType = MessageCoder.getBytes(data.getContentType());
|
||||||
|
byte[] headers = MessageCoder.getBytes(data.getHeaders());
|
||||||
|
byte[] cookies = getBytes(data.getCookies());
|
||||||
|
byte[] content;
|
||||||
|
if (data.getResult() == null) {
|
||||||
|
content = new byte[0]; //""
|
||||||
|
} else if (data.getResult() instanceof byte[]) {
|
||||||
|
content = (byte[]) data.getResult();
|
||||||
|
} else if (data.getResult() instanceof CharSequence) {
|
||||||
|
content = MessageCoder.getBytes(data.getResult().toString());
|
||||||
|
} else {
|
||||||
|
Convert cc = data.convert();
|
||||||
|
if (cc == null || !(cc instanceof TextConvert)) cc = JsonConvert.root();
|
||||||
|
content = cc.convertToBytes(data.getResult());
|
||||||
|
}
|
||||||
|
int count = 4 + 2 + contentType.length + headers.length + cookies.length + 4 + (content == null ? 0 : content.length);
|
||||||
|
final byte[] bs = new byte[count];
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(bs);
|
||||||
|
buffer.putInt(data.getStatus());
|
||||||
|
buffer.putChar((char) contentType.length);
|
||||||
|
if (contentType.length > 0) buffer.put(contentType);
|
||||||
|
buffer.put(headers);
|
||||||
|
buffer.put(cookies);
|
||||||
|
if (content == null || content.length == 0) {
|
||||||
|
buffer.putInt(0);
|
||||||
|
} else {
|
||||||
|
buffer.putInt(content.length);
|
||||||
|
buffer.put(content);
|
||||||
|
}
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpResult<byte[]> decode(byte[] data) {
|
||||||
|
if (data == null) return null;
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||||
|
HttpResult result = new HttpResult();
|
||||||
|
result.setStatus(buffer.getInt());
|
||||||
|
result.setContentType(MessageCoder.getShortString(buffer));
|
||||||
|
result.setHeaders(MessageCoder.getMap(buffer));
|
||||||
|
result.setCookies(getCookieList(buffer));
|
||||||
|
int len = buffer.getInt();
|
||||||
|
if (len > 0) {
|
||||||
|
byte[] bs = new byte[len];
|
||||||
|
buffer.get(bs);
|
||||||
|
result.setResult(bs);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] getBytes(final List<HttpCookie> list) {
|
||||||
|
if (list == null || list.isEmpty()) return new byte[2];
|
||||||
|
final AtomicInteger len = new AtomicInteger(2);
|
||||||
|
list.forEach(cookie -> {
|
||||||
|
len.addAndGet(2 + (cookie.getName() == null ? 0 : Utility.encodeUTF8Length(cookie.getName())));
|
||||||
|
len.addAndGet(2 + (cookie.getValue() == null ? 0 : Utility.encodeUTF8Length(cookie.getValue())));
|
||||||
|
len.addAndGet(2 + (cookie.getDomain() == null ? 0 : Utility.encodeUTF8Length(cookie.getDomain())));
|
||||||
|
len.addAndGet(2 + (cookie.getPath() == null ? 0 : Utility.encodeUTF8Length(cookie.getPath())));
|
||||||
|
len.addAndGet(2 + (cookie.getPortlist() == null ? 0 : Utility.encodeUTF8Length(cookie.getPortlist())));
|
||||||
|
len.addAndGet(8 + 1 + 1); //maxage Secure HttpOnly
|
||||||
|
});
|
||||||
|
final byte[] bs = new byte[len.get()];
|
||||||
|
final ByteBuffer buffer = ByteBuffer.wrap(bs);
|
||||||
|
buffer.putChar((char) list.size());
|
||||||
|
list.forEach(cookie -> {
|
||||||
|
putShortString(buffer, cookie.getName());
|
||||||
|
putShortString(buffer, cookie.getValue());
|
||||||
|
putShortString(buffer, cookie.getDomain());
|
||||||
|
putShortString(buffer, cookie.getPath());
|
||||||
|
putShortString(buffer, cookie.getPortlist());
|
||||||
|
buffer.putLong(cookie.getMaxAge());
|
||||||
|
buffer.put(cookie.getSecure() ? (byte) 1 : (byte) 0);
|
||||||
|
buffer.put(cookie.isHttpOnly() ? (byte) 1 : (byte) 0);
|
||||||
|
});
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<HttpCookie> getCookieList(ByteBuffer buffer) {
|
||||||
|
int len = buffer.getChar();
|
||||||
|
if (len == 0) return null;
|
||||||
|
final List<HttpCookie> list = new ArrayList<>(len);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
HttpCookie cookie = new HttpCookie(getShortString(buffer), getShortString(buffer));
|
||||||
|
cookie.setDomain(getShortString(buffer));
|
||||||
|
cookie.setPath(getShortString(buffer));
|
||||||
|
cookie.setPortlist(getShortString(buffer));
|
||||||
|
cookie.setMaxAge(buffer.getLong());
|
||||||
|
cookie.setSecure(buffer.get() == 1);
|
||||||
|
cookie.setHttpOnly(buffer.get() == 1);
|
||||||
|
list.add(cookie);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
93
src/org/redkale/mq/HttpSimpleRequestCoder.java
Normal file
93
src/org/redkale/mq/HttpSimpleRequestCoder.java
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import org.redkale.net.http.HttpSimpleRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpSimpleRequest的MessageCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class HttpSimpleRequestCoder implements MessageCoder<HttpSimpleRequest> {
|
||||||
|
|
||||||
|
private static final HttpSimpleRequestCoder instance = new HttpSimpleRequestCoder();
|
||||||
|
|
||||||
|
public static HttpSimpleRequestCoder getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encode(HttpSimpleRequest data) {
|
||||||
|
byte[] requestURI = MessageCoder.getBytes(data.getRequestURI()); //long-string
|
||||||
|
byte[] path = MessageCoder.getBytes(data.getRequestURI()); //short-string
|
||||||
|
byte[] remoteAddr = MessageCoder.getBytes(data.getRemoteAddr());//short-string
|
||||||
|
byte[] sessionid = MessageCoder.getBytes(data.getSessionid());//short-string
|
||||||
|
byte[] contentType = MessageCoder.getBytes(data.getContentType());//short-string
|
||||||
|
byte[] headers = MessageCoder.getBytes(data.getHeaders());
|
||||||
|
byte[] params = MessageCoder.getBytes(data.getParams());
|
||||||
|
byte[] body = MessageCoder.getBytes(data.getBody());
|
||||||
|
int count = 1 + 4 + requestURI.length + 2 + path.length + 2 + remoteAddr.length + 2 + sessionid.length
|
||||||
|
+ 2 + contentType.length + 4 + headers.length + params.length + 4 + body.length;
|
||||||
|
byte[] bs = new byte[count];
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(bs);
|
||||||
|
buffer.put((byte) (data.isRpc() ? 'T' : 'F'));
|
||||||
|
buffer.putInt(requestURI.length);
|
||||||
|
if (requestURI.length > 0) buffer.put(requestURI);
|
||||||
|
buffer.putChar((char) path.length);
|
||||||
|
if (path.length > 0) buffer.put(path);
|
||||||
|
buffer.putChar((char) remoteAddr.length);
|
||||||
|
if (remoteAddr.length > 0) buffer.put(remoteAddr);
|
||||||
|
buffer.putChar((char) sessionid.length);
|
||||||
|
if (sessionid.length > 0) buffer.put(sessionid);
|
||||||
|
buffer.putChar((char) contentType.length);
|
||||||
|
if (contentType.length > 0) buffer.put(contentType);
|
||||||
|
buffer.putInt(data.getCurrentUserid());
|
||||||
|
buffer.put(headers);
|
||||||
|
buffer.put(params);
|
||||||
|
buffer.putInt(body.length);
|
||||||
|
if (body.length > 0) buffer.put(body);
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpSimpleRequest decode(byte[] data) {
|
||||||
|
if (data == null) return null;
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||||
|
HttpSimpleRequest req = new HttpSimpleRequest();
|
||||||
|
req.setRpc(buffer.get() == 'T');
|
||||||
|
req.setRequestURI(MessageCoder.getLongString(buffer));
|
||||||
|
req.setPath(MessageCoder.getShortString(buffer));
|
||||||
|
req.setRemoteAddr(MessageCoder.getShortString(buffer));
|
||||||
|
req.setSessionid(MessageCoder.getShortString(buffer));
|
||||||
|
req.setContentType(MessageCoder.getShortString(buffer));
|
||||||
|
req.setCurrentUserid(buffer.getInt());
|
||||||
|
req.setHeaders(MessageCoder.getMap(buffer));
|
||||||
|
req.setParams(MessageCoder.getMap(buffer));
|
||||||
|
int len = buffer.getInt();
|
||||||
|
if (len > 0) {
|
||||||
|
byte[] bs = new byte[len];
|
||||||
|
buffer.get(bs);
|
||||||
|
req.setBody(bs);
|
||||||
|
}
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getString(ByteBuffer buffer) {
|
||||||
|
int len = buffer.getInt();
|
||||||
|
if (len == 0) return null;
|
||||||
|
byte[] bs = new byte[len];
|
||||||
|
buffer.get(bs);
|
||||||
|
return new String(bs, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
||||||
308
src/org/redkale/mq/MessageAgent.java
Normal file
308
src/org/redkale/mq/MessageAgent.java
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.*;
|
||||||
|
import static org.redkale.boot.Application.RESNAME_APP_NODEID;
|
||||||
|
import org.redkale.net.Servlet;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.service.Service;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQ管理器
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public abstract class MessageAgent {
|
||||||
|
|
||||||
|
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
|
|
||||||
|
@Resource(name = RESNAME_APP_NODEID)
|
||||||
|
protected int nodeid;
|
||||||
|
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
protected AnyValue config;
|
||||||
|
|
||||||
|
protected MessageProducers httpProducer;
|
||||||
|
|
||||||
|
protected MessageProducers sncpProducer;
|
||||||
|
|
||||||
|
protected final Object httpProducerLock = new Object();
|
||||||
|
|
||||||
|
protected final Object sncpProducerLock = new Object();
|
||||||
|
|
||||||
|
protected HttpMessageClient httpMessageClient;
|
||||||
|
|
||||||
|
protected SncpMessageClient sncpMessageClient;
|
||||||
|
|
||||||
|
protected ScheduledThreadPoolExecutor timeoutExecutor;
|
||||||
|
|
||||||
|
protected ThreadHashExecutor workExecutor;
|
||||||
|
|
||||||
|
//本地Service消息接收处理器, key:consumer
|
||||||
|
protected HashMap<String, MessageConsumerNode> messageNodes = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public void init(AnyValue config) {
|
||||||
|
this.name = checkName(config.getValue("name", ""));
|
||||||
|
this.httpMessageClient = new HttpMessageClient(this);
|
||||||
|
this.sncpMessageClient = new SncpMessageClient(this);
|
||||||
|
this.workExecutor = new ThreadHashExecutor(Math.max(4, config.getIntValue("threads", Runtime.getRuntime().availableProcessors())));
|
||||||
|
// application (it doesn't execute completion handlers).
|
||||||
|
this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> {
|
||||||
|
Thread t = new Thread(r);
|
||||||
|
t.setName("MessageAgent-Timeout-Thread");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
this.timeoutExecutor.setRemoveOnCancelPolicy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Map<String, Long>> start() {
|
||||||
|
final LinkedHashMap<String, Long> map = new LinkedHashMap<>();
|
||||||
|
final List<CompletableFuture> futures = new ArrayList<>();
|
||||||
|
this.messageNodes.values().forEach(node -> {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
futures.add(node.consumer.startup().whenComplete((r, t) -> map.put(node.consumer.consumerid, System.currentTimeMillis() - s)));
|
||||||
|
});
|
||||||
|
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(r -> map);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Application.shutdown 在执行server.shutdown之前执行
|
||||||
|
public CompletableFuture<Void> stop() {
|
||||||
|
List<CompletableFuture> futures = new ArrayList<>();
|
||||||
|
this.messageNodes.values().forEach(node -> {
|
||||||
|
futures.add(node.consumer.shutdown());
|
||||||
|
});
|
||||||
|
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Application.shutdown 在所有server.shutdown执行后执行
|
||||||
|
public void destroy(AnyValue config) {
|
||||||
|
this.httpMessageClient.close().join();
|
||||||
|
this.sncpMessageClient.close().join();
|
||||||
|
this.workExecutor.shutdown();
|
||||||
|
if (this.timeoutExecutor != null) this.timeoutExecutor.shutdown();
|
||||||
|
if (this.sncpProducer != null) this.sncpProducer.shutdown().join();
|
||||||
|
if (this.httpProducer != null) this.httpProducer.shutdown().join();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<MessageConsumer> getAllMessageConsumer() {
|
||||||
|
List<MessageConsumer> consumers = new ArrayList<>();
|
||||||
|
MessageConsumer one = this.httpMessageClient == null ? null : this.httpMessageClient.consumer;
|
||||||
|
if (one != null) consumers.add(one);
|
||||||
|
one = this.sncpMessageClient == null ? null : this.sncpMessageClient.consumer;
|
||||||
|
if (one != null) consumers.add(one);
|
||||||
|
consumers.addAll(messageNodes.values().stream().map(mcn -> mcn.consumer).collect(Collectors.toList()));
|
||||||
|
return consumers;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<MessageProducer> getAllMessageProducer() {
|
||||||
|
List<MessageProducer> producers = new ArrayList<>();
|
||||||
|
if (this.httpProducer != null) producers.addAll(List.of(this.httpProducer.producers));
|
||||||
|
if (this.sncpProducer != null) producers.addAll(List.of(this.sncpProducer.producers));
|
||||||
|
MessageProducers one = this.httpMessageClient == null ? null : this.httpMessageClient.getProducer();
|
||||||
|
if (one != null) producers.addAll(List.of(one.producers));
|
||||||
|
one = this.sncpMessageClient == null ? null : this.sncpMessageClient.getProducer();
|
||||||
|
if (one != null) producers.addAll(List.of(one.producers));
|
||||||
|
return producers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Logger getLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnyValue getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfig(AnyValue config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpMessageClient getHttpMessageClient() {
|
||||||
|
return httpMessageClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SncpMessageClient getSncpMessageClient() {
|
||||||
|
return sncpMessageClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String checkName(String name) { //不能含特殊字符
|
||||||
|
if (name.isEmpty()) return name;
|
||||||
|
if (name.charAt(0) >= '0' && name.charAt(0) <= '9') throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9");
|
||||||
|
for (char ch : name.toCharArray()) {
|
||||||
|
if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //不能含特殊字符
|
||||||
|
throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取指定topic的生产处理器
|
||||||
|
public MessageProducers getSncpProducer() {
|
||||||
|
if (this.sncpProducer == null) {
|
||||||
|
synchronized (sncpProducerLock) {
|
||||||
|
if (this.sncpProducer == null) {
|
||||||
|
MessageProducer[] producers = new MessageProducer[Runtime.getRuntime().availableProcessors()];
|
||||||
|
for (int i = 0; i < producers.length; i++) {
|
||||||
|
MessageProducer producer = createProducer("SncpProducer");
|
||||||
|
producer.startup().join();
|
||||||
|
producers[i] = producer;
|
||||||
|
}
|
||||||
|
this.sncpProducer = new MessageProducers(producers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.sncpProducer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageProducers getHttpProducer() {
|
||||||
|
if (this.httpProducer == null) {
|
||||||
|
synchronized (httpProducerLock) {
|
||||||
|
if (this.httpProducer == null) {
|
||||||
|
MessageProducer[] producers = new MessageProducer[Runtime.getRuntime().availableProcessors()];
|
||||||
|
for (int i = 0; i < producers.length; i++) {
|
||||||
|
MessageProducer producer = createProducer("HttpProducer");
|
||||||
|
producer.startup().join();
|
||||||
|
producers[i] = producer;
|
||||||
|
}
|
||||||
|
this.httpProducer = new MessageProducers(producers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.httpProducer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建指定topic的生产处理器
|
||||||
|
protected abstract MessageProducer createProducer(String name);
|
||||||
|
|
||||||
|
//创建topic,如果已存在则跳过
|
||||||
|
public abstract boolean createTopic(String... topics);
|
||||||
|
|
||||||
|
//删除topic,如果不存在则跳过
|
||||||
|
public abstract boolean deleteTopic(String... topics);
|
||||||
|
|
||||||
|
//查询所有topic
|
||||||
|
public abstract List<String> queryTopic();
|
||||||
|
|
||||||
|
//ServiceLoader时判断配置是否符合当前实现类
|
||||||
|
public abstract boolean match(AnyValue config);
|
||||||
|
|
||||||
|
//创建指定topic的消费处理器
|
||||||
|
public abstract MessageConsumer createConsumer(String[] topics, String group, MessageProcessor processor);
|
||||||
|
|
||||||
|
public final synchronized void putService(NodeHttpServer ns, Service service, HttpServlet servlet) {
|
||||||
|
String[] topics = generateHttpReqTopics(service);
|
||||||
|
String consumerid = generateHttpConsumerid(topics, service);
|
||||||
|
if (messageNodes.containsKey(consumerid)) throw new RuntimeException("consumerid(" + consumerid + ") is repeat");
|
||||||
|
HttpMessageProcessor processor = new HttpMessageProcessor(this.logger, this.workExecutor, getHttpProducer(), ns, service, servlet);
|
||||||
|
this.messageNodes.put(consumerid, new MessageConsumerNode(ns, service, servlet, processor, createConsumer(topics, consumerid, processor)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final synchronized void putService(NodeSncpServer ns, Service service, SncpServlet servlet) {
|
||||||
|
String topic = generateSncpReqTopic(service);
|
||||||
|
String consumerid = generateSncpConsumerid(topic, service);
|
||||||
|
if (messageNodes.containsKey(consumerid)) throw new RuntimeException("consumerid(" + consumerid + ") is repeat");
|
||||||
|
SncpMessageProcessor processor = new SncpMessageProcessor(this.logger, this.workExecutor, getSncpProducer(), ns, service, servlet);
|
||||||
|
this.messageNodes.put(consumerid, new MessageConsumerNode(ns, service, servlet, processor, createConsumer(new String[]{topic}, consumerid, processor)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: sncp.req.user
|
||||||
|
public final String generateSncpReqTopic(Service service) {
|
||||||
|
if (service instanceof WebSocketNode) {
|
||||||
|
String resname = Sncp.getResourceName(service);
|
||||||
|
return "sncp.req.ws" + (resname.isEmpty() ? "" : ("-" + resname)) + ".node" + nodeid;
|
||||||
|
}
|
||||||
|
String resname = Sncp.getResourceName(service);
|
||||||
|
return "sncp.req." + Sncp.getResourceType(service).getSimpleName().replaceAll("Service.*$", "").toLowerCase() + (resname.isEmpty() ? "" : ("-" + resname));
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: consumer-sncp.req.user 不提供外部使用
|
||||||
|
protected final String generateSncpConsumerid(String topic, Service service) {
|
||||||
|
return "consumer-" + topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: http.req.user
|
||||||
|
public static String generateHttpReqTopic(String module) {
|
||||||
|
return "http.req." + module.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: http.req.user
|
||||||
|
public static String generateHttpReqTopic(String module, String resname) {
|
||||||
|
return "http.req." + module.toLowerCase() + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: sncp.resp.node10
|
||||||
|
protected String generateSncpRespTopic() {
|
||||||
|
return "sncp.resp.node" + nodeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: http.resp.node10
|
||||||
|
protected String generateHttpRespTopic() {
|
||||||
|
return "http.resp.node" + nodeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: http.req.user
|
||||||
|
protected String[] generateHttpReqTopics(Service service) {
|
||||||
|
String resname = Sncp.getResourceName(service);
|
||||||
|
String module = Rest.getRestModule(service).toLowerCase();
|
||||||
|
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
|
||||||
|
if (mmc != null) return new String[]{generateHttpReqTopic(mmc.module()) + (resname.isEmpty() ? "" : ("-" + resname))};
|
||||||
|
return new String[]{"http.req." + module + (resname.isEmpty() ? "" : ("-" + resname))};
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: consumer-http.req.user
|
||||||
|
protected String generateHttpConsumerid(String[] topics, Service service) {
|
||||||
|
String resname = Sncp.getResourceName(service);
|
||||||
|
String key = Rest.getRestModule(service).toLowerCase();
|
||||||
|
return "consumer-http.req." + key + (resname.isEmpty() ? "" : ("-" + resname));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: xxxx.resp.node10
|
||||||
|
protected String generateRespTopic(String protocol) {
|
||||||
|
return protocol + ".resp.node" + nodeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class MessageConsumerNode {
|
||||||
|
|
||||||
|
public final NodeServer server;
|
||||||
|
|
||||||
|
public final Service service;
|
||||||
|
|
||||||
|
public final Servlet servlet;
|
||||||
|
|
||||||
|
public final MessageProcessor processor;
|
||||||
|
|
||||||
|
public final MessageConsumer consumer;
|
||||||
|
|
||||||
|
public MessageConsumerNode(NodeServer server, Service service, Servlet servlet, MessageProcessor processor, MessageConsumer consumer) {
|
||||||
|
this.server = server;
|
||||||
|
this.service = service;
|
||||||
|
this.servlet = servlet;
|
||||||
|
this.processor = processor;
|
||||||
|
this.consumer = consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/org/redkale/mq/MessageClient.java
Normal file
89
src/org/redkale/mq/MessageClient.java
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.redkale.convert.ConvertType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public abstract class MessageClient {
|
||||||
|
|
||||||
|
protected final ConcurrentHashMap<Long, MessageRespFutureNode> respNodes = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
protected final MessageAgent messageAgent;
|
||||||
|
|
||||||
|
protected MessageConsumer consumer;
|
||||||
|
|
||||||
|
protected String respTopic;
|
||||||
|
|
||||||
|
protected String respConsumerid;
|
||||||
|
|
||||||
|
protected ConvertType convertType;
|
||||||
|
|
||||||
|
protected MessageClient(MessageAgent messageAgent) {
|
||||||
|
this.messageAgent = messageAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CompletableFuture<Void> close() {
|
||||||
|
if (this.consumer == null) return CompletableFuture.completedFuture(null);
|
||||||
|
return this.consumer.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CompletableFuture<MessageRecord> sendMessage(MessageRecord message, boolean needresp, AtomicLong counter) {
|
||||||
|
CompletableFuture<MessageRecord> future = new CompletableFuture<>();
|
||||||
|
try {
|
||||||
|
if (this.consumer == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (this.respConsumerid == null) this.respConsumerid = "consumer-" + this.respTopic;
|
||||||
|
if (this.consumer == null) {
|
||||||
|
MessageProcessor processor = (msg, callback) -> {
|
||||||
|
MessageRespFutureNode node = respNodes.remove(msg.getSeqid());
|
||||||
|
if (node == null) {
|
||||||
|
messageAgent.logger.log(Level.WARNING, MessageClient.this.getClass().getSimpleName() + " process " + msg + " error, not found msgnode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node.getCounter() != null) node.getCounter().decrementAndGet();
|
||||||
|
node.future.complete(msg);
|
||||||
|
};
|
||||||
|
MessageConsumer one = messageAgent.createConsumer(new String[]{respTopic}, respConsumerid, processor);
|
||||||
|
one.startup().join();
|
||||||
|
this.consumer = one;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (convertType != null) message.setFormat(convertType);
|
||||||
|
if (needresp && (message.getResptopic() == null || message.getResptopic().isEmpty())) {
|
||||||
|
message.setResptopic(respTopic);
|
||||||
|
}
|
||||||
|
if (counter != null) counter.incrementAndGet();
|
||||||
|
getProducer().apply(message);
|
||||||
|
if (needresp) {
|
||||||
|
MessageRespFutureNode node = new MessageRespFutureNode(message, respNodes, counter, future);
|
||||||
|
respNodes.put(message.getSeqid(), node);
|
||||||
|
ScheduledThreadPoolExecutor executor = messageAgent.timeoutExecutor;
|
||||||
|
if (executor != null) executor.schedule(node, 30, TimeUnit.SECONDS);
|
||||||
|
} else {
|
||||||
|
future.complete(null);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
future.completeExceptionally(ex);
|
||||||
|
} finally {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract MessageProducers getProducer();
|
||||||
|
}
|
||||||
107
src/org/redkale/mq/MessageCoder.java
Normal file
107
src/org/redkale/mq/MessageCoder.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将MessageRecord.content内容加解密
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
*/
|
||||||
|
public interface MessageCoder<T> {
|
||||||
|
|
||||||
|
//编码
|
||||||
|
public byte[] encode(T data);
|
||||||
|
|
||||||
|
//解码
|
||||||
|
public T decode(byte[] data);
|
||||||
|
|
||||||
|
public static byte[] getBytes(byte[] value) {
|
||||||
|
if (value == null) return MessageRecord.EMPTY_BYTES;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] getBytes(String value) {
|
||||||
|
if (value == null || value.isEmpty()) return MessageRecord.EMPTY_BYTES;
|
||||||
|
return value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] getBytes(final Map<String, String> map) {
|
||||||
|
if (map == null || map.isEmpty()) return new byte[2];
|
||||||
|
final AtomicInteger len = new AtomicInteger(2);
|
||||||
|
map.forEach((key, value) -> {
|
||||||
|
len.addAndGet(2 + (key == null ? 0 : Utility.encodeUTF8Length(key)));
|
||||||
|
len.addAndGet(4 + (value == null ? 0 : Utility.encodeUTF8Length(value)));
|
||||||
|
});
|
||||||
|
final byte[] bs = new byte[len.get()];
|
||||||
|
final ByteBuffer buffer = ByteBuffer.wrap(bs);
|
||||||
|
buffer.putChar((char) map.size());
|
||||||
|
map.forEach((key, value) -> {
|
||||||
|
putShortString(buffer, key);
|
||||||
|
putLongString(buffer, value);
|
||||||
|
});
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void putLongString(ByteBuffer buffer, String value) {
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
buffer.putInt(0);
|
||||||
|
} else {
|
||||||
|
byte[] bs = value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
buffer.putInt(bs.length);
|
||||||
|
buffer.put(bs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLongString(ByteBuffer buffer) {
|
||||||
|
int len = buffer.getInt();
|
||||||
|
if (len == 0) return null;
|
||||||
|
byte[] bs = new byte[len];
|
||||||
|
buffer.get(bs);
|
||||||
|
return new String(bs, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void putShortString(ByteBuffer buffer, String value) {
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
buffer.putChar((char) 0);
|
||||||
|
} else {
|
||||||
|
byte[] bs = value.getBytes(StandardCharsets.UTF_8);
|
||||||
|
buffer.putChar((char) bs.length);
|
||||||
|
buffer.put(bs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getShortString(ByteBuffer buffer) {
|
||||||
|
int len = buffer.getChar();
|
||||||
|
if (len == 0) return null;
|
||||||
|
byte[] bs = new byte[len];
|
||||||
|
buffer.get(bs);
|
||||||
|
return new String(bs, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> getMap(ByteBuffer buffer) {
|
||||||
|
int len = buffer.getChar();
|
||||||
|
if (len == 0) return null;
|
||||||
|
Map<String, String> map = new HashMap<>(len);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
map.put(getShortString(buffer), getLongString(buffer));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/org/redkale/mq/MessageConsumer.java
Normal file
63
src/org/redkale/mq/MessageConsumer.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public abstract class MessageConsumer {
|
||||||
|
|
||||||
|
protected final String[] topics;
|
||||||
|
|
||||||
|
protected final String consumerid;
|
||||||
|
|
||||||
|
protected MessageAgent messageAgent;
|
||||||
|
|
||||||
|
protected final MessageProcessor processor;
|
||||||
|
|
||||||
|
protected final Logger logger;
|
||||||
|
|
||||||
|
protected volatile boolean closed;
|
||||||
|
|
||||||
|
protected MessageConsumer(MessageAgent messageAgent, String[] topics, final String consumerid, MessageProcessor processor) {
|
||||||
|
Objects.requireNonNull(messageAgent);
|
||||||
|
Objects.requireNonNull(topics);
|
||||||
|
Objects.requireNonNull(consumerid);
|
||||||
|
Objects.requireNonNull(processor);
|
||||||
|
this.messageAgent = messageAgent;
|
||||||
|
this.logger = messageAgent.logger;
|
||||||
|
this.topics = topics;
|
||||||
|
this.consumerid = consumerid;
|
||||||
|
this.processor = processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageProcessor getProcessor() {
|
||||||
|
return processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getTopics() {
|
||||||
|
return topics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract CompletableFuture<Void> startup();
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract CompletableFuture<Void> shutdown();
|
||||||
|
}
|
||||||
61
src/org/redkale/mq/MessageMultiConsumer.java
Normal file
61
src/org/redkale/mq/MessageMultiConsumer.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.mq;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
import static java.lang.annotation.ElementType.*;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多消费组,需要同 @RestService 一起使用
|
||||||
|
* <p>
|
||||||
|
* 通常一个topic只会被一个RestService消费, 当一个topic需要被其他RestService消费时,就需要使用@MessageMultiConsumer
|
||||||
|
*
|
||||||
|
* <blockquote><pre>
|
||||||
|
* @RestService(name = "user", comment = "用户服务")
|
||||||
|
* public class UserService implements Service{
|
||||||
|
*
|
||||||
|
* @RestMapping(comment = "用户登录")
|
||||||
|
* public RetResult login(LoginBean bean){
|
||||||
|
* //do something
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre></blockquote>
|
||||||
|
*
|
||||||
|
* 需求:统计用户登录次数, 可以创建一个MessageMultiConsumer 的 RestService:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* <b>@MessageMultiConsumer(module = "user") </b>
|
||||||
|
* @RestService(name = "loginstat", comment = "用户统计服务")
|
||||||
|
* public class LoginStatService implements Service{
|
||||||
|
*
|
||||||
|
* private AtomicLong counter = new AtomicLong();
|
||||||
|
*
|
||||||
|
* @RestMapping(name = "login", comment = "用户登录统计")
|
||||||
|
* public void stat(LoginBean bean){ //参数必须和UserService.login方法一致
|
||||||
|
* counter.incrementAndGet();
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre></blockquote>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 注: 标记 @MessageMultiConsumer 的Service的@RestMapping方法都只能是void返回类型
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target({TYPE})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface MessageMultiConsumer {
|
||||||
|
|
||||||
|
String module();
|
||||||
|
}
|
||||||
26
src/org/redkale/mq/MessageProcessor.java
Normal file
26
src/org/redkale/mq/MessageProcessor.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.mq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public interface MessageProcessor {
|
||||||
|
|
||||||
|
default void begin(int size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void process(MessageRecord message, Runnable callback);
|
||||||
|
|
||||||
|
default void commit() {
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/org/redkale/mq/MessageProducer.java
Normal file
42
src/org/redkale/mq/MessageProducer.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public abstract class MessageProducer {
|
||||||
|
|
||||||
|
protected final Logger logger;
|
||||||
|
|
||||||
|
protected final String name;
|
||||||
|
|
||||||
|
protected volatile boolean closed;
|
||||||
|
|
||||||
|
protected MessageProducer(String name, Logger logger) {
|
||||||
|
this.name = name;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract CompletableFuture<Void> apply(MessageRecord message);
|
||||||
|
|
||||||
|
public abstract CompletableFuture<Void> startup();
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract CompletableFuture<Void> shutdown();
|
||||||
|
}
|
||||||
61
src/org/redkale/mq/MessageProducers.java
Normal file
61
src/org/redkale/mq/MessageProducers.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.mq;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class MessageProducers {
|
||||||
|
|
||||||
|
protected final MessageProducer[] producers;
|
||||||
|
|
||||||
|
protected final AtomicInteger index = new AtomicInteger();
|
||||||
|
|
||||||
|
public MessageProducers(MessageProducer[] producers) {
|
||||||
|
this.producers = producers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageProducer getProducer(MessageRecord message) {
|
||||||
|
int hash = index.incrementAndGet();
|
||||||
|
if (index.get() > 1000 * producers.length) {
|
||||||
|
synchronized (index) {
|
||||||
|
if (index.get() > 1000 * producers.length) {
|
||||||
|
index.addAndGet(-1000 * producers.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return producers[hash % producers.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Void> apply(MessageRecord message) {
|
||||||
|
return getProducer(message).apply(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Void> startup() {
|
||||||
|
CompletableFuture[] futures = new CompletableFuture[producers.length];
|
||||||
|
for (int i = 0; i < producers.length; i++) {
|
||||||
|
futures[i] = producers[i].startup();
|
||||||
|
}
|
||||||
|
return CompletableFuture.allOf(futures);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Void> shutdown() {
|
||||||
|
CompletableFuture[] futures = new CompletableFuture[producers.length];
|
||||||
|
for (int i = 0; i < producers.length; i++) {
|
||||||
|
futures[i] = producers[i].shutdown();
|
||||||
|
}
|
||||||
|
return CompletableFuture.allOf(futures);
|
||||||
|
}
|
||||||
|
}
|
||||||
320
src/org/redkale/mq/MessageRecord.java
Normal file
320
src/org/redkale/mq/MessageRecord.java
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.util.Comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存在MQ里面的数据结构<p>
|
||||||
|
* groupid + userid 来确定partition, 优先使用 groupid
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class MessageRecord implements Serializable {
|
||||||
|
|
||||||
|
static final byte[] EMPTY_BYTES = new byte[0];
|
||||||
|
|
||||||
|
@ConvertColumn(index = 1)
|
||||||
|
@Comment("消息序列号")
|
||||||
|
protected long seqid;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 2)
|
||||||
|
@Comment("版本")
|
||||||
|
protected int version;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 3)
|
||||||
|
@Comment("内容的格式, 只能是JSON、BSON、PROTOBUF、DIY和null, 普通文本也归于JSON")
|
||||||
|
protected ConvertType format;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 4)
|
||||||
|
@Comment("标记位, 自定义时使用")
|
||||||
|
protected int flag;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 5)
|
||||||
|
@Comment("创建时间")
|
||||||
|
protected long createtime;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 6)
|
||||||
|
@Comment("用户ID,无用户信息视为0")
|
||||||
|
protected int userid;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 7)
|
||||||
|
@Comment("组ID")
|
||||||
|
protected String groupid;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 8)
|
||||||
|
@Comment("当前topic")
|
||||||
|
protected String topic;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 9)
|
||||||
|
@Comment("目标topic, 为空表示无目标topic")
|
||||||
|
protected String resptopic;
|
||||||
|
|
||||||
|
@ConvertColumn(index = 10)
|
||||||
|
@Comment("消息内容")
|
||||||
|
protected byte[] content;
|
||||||
|
|
||||||
|
public MessageRecord() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(String resptopic, String content) {
|
||||||
|
this(System.nanoTime(), content == null ? null : ConvertType.JSON, 0, 0, null, null, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(String topic, String resptopic, String content) {
|
||||||
|
this(System.nanoTime(), content == null ? null : ConvertType.JSON, 0, 0, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(int userid, String topic, String resptopic, String content) {
|
||||||
|
this(System.nanoTime(), content == null ? null : ConvertType.JSON, 0, userid, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(ConvertType format, String topic, String resptopic, byte[] content) {
|
||||||
|
this(System.nanoTime(), format, 0, 0, null, topic, resptopic, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(long seqid, ConvertType format, String topic, String resptopic, byte[] content) {
|
||||||
|
this(seqid, format, 0, null, topic, resptopic, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(long seqid, ConvertType format, int userid, String groupid, String topic, String resptopic, byte[] content) {
|
||||||
|
this(seqid, format, 0, userid, groupid, topic, resptopic, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(String topic, String resptopic, Convert convert, Object bean) {
|
||||||
|
this(0, null, topic, resptopic, convert, bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(int userid, String topic, String resptopic, Convert convert, Object bean) {
|
||||||
|
this(userid, null, topic, resptopic, convert, bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) {
|
||||||
|
this(0, userid, groupid, topic, resptopic, convert, bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(int flag, int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) {
|
||||||
|
this(System.nanoTime(), convert.getFactory().getConvertType(), flag, userid, groupid, topic, resptopic, convert.convertToBytes(bean));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(long seqid, ConvertType format, int flag, int userid, String groupid, String topic, String resptopic, byte[] content) {
|
||||||
|
this(seqid, 1, format, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord(long seqid, int version, ConvertType format, int flag, long createtime, int userid, String groupid, String topic, String resptopic, byte[] content) {
|
||||||
|
this.seqid = seqid;
|
||||||
|
this.version = version;
|
||||||
|
this.format = format;
|
||||||
|
this.flag = flag;
|
||||||
|
this.createtime = createtime;
|
||||||
|
this.userid = userid;
|
||||||
|
this.groupid = groupid;
|
||||||
|
this.topic = topic;
|
||||||
|
this.resptopic = resptopic;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String contentString() {
|
||||||
|
return content == null ? null : new String(content, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConvertDisabled
|
||||||
|
public boolean isEmptyTopic() {
|
||||||
|
return this.topic == null || this.topic.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConvertDisabled
|
||||||
|
public boolean isEmptyResptopic() {
|
||||||
|
return this.resptopic == null || this.resptopic.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T convertFromContent(Convert convert, java.lang.reflect.Type type) {
|
||||||
|
if (this.content == null || this.content.length == 0) return null;
|
||||||
|
return (T) convert.convertFrom(type, this.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T decodeContent(MessageCoder<T> coder) {
|
||||||
|
if (this.content == null || this.content.length == 0) return null;
|
||||||
|
return (T) coder.decode(this.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> MessageRecord encodeContent(MessageCoder<T> coder, T data) {
|
||||||
|
this.content = coder.encode(data);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hash() {
|
||||||
|
if (groupid != null && !groupid.isEmpty()) {
|
||||||
|
return groupid.hashCode();
|
||||||
|
} else if (userid > 0) {
|
||||||
|
return userid;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord version(int version) {
|
||||||
|
this.version = version;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord format(ConvertType format) {
|
||||||
|
this.format = format;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord flag(int flag) {
|
||||||
|
this.flag = flag;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord createtime(long createtime) {
|
||||||
|
this.createtime = createtime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord userid(int userid) {
|
||||||
|
this.userid = userid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord groupid(String groupid) {
|
||||||
|
this.groupid = groupid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord topic(String topic) {
|
||||||
|
this.topic = topic;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord resptopic(String resptopic) {
|
||||||
|
this.resptopic = resptopic;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord content(byte[] content) {
|
||||||
|
this.content = content;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRecord contentString(String content) {
|
||||||
|
this.content = content == null ? null : content.getBytes(StandardCharsets.UTF_8);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSeqid() {
|
||||||
|
return seqid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeqid(long seqid) {
|
||||||
|
this.seqid = seqid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(int version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertType getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFormat(ConvertType format) {
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlag() {
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlag(int flag) {
|
||||||
|
this.flag = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCreatetime() {
|
||||||
|
return createtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatetime(long createtime) {
|
||||||
|
this.createtime = createtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUserid() {
|
||||||
|
return userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserid(int userid) {
|
||||||
|
this.userid = userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupid() {
|
||||||
|
return groupid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupid(String groupid) {
|
||||||
|
this.groupid = groupid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTopic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopic(String topic) {
|
||||||
|
this.topic = topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResptopic() {
|
||||||
|
return resptopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResptopic(String resptopic) {
|
||||||
|
this.resptopic = resptopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(byte[] content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
//return JsonConvert.root().convertTo(this);
|
||||||
|
StringBuilder sb = new StringBuilder(128);
|
||||||
|
sb.append("{\"seqid\":").append(this.seqid);
|
||||||
|
sb.append(",\"version\":").append(this.version);
|
||||||
|
if (this.format != null) sb.append(",\"format\":\"").append(this.format).append("\"");
|
||||||
|
if (this.flag != 0) sb.append(",\"flag\":").append(this.flag);
|
||||||
|
if (this.createtime != 0) sb.append(",\"createtime\":").append(this.createtime);
|
||||||
|
if (this.userid != 0) sb.append(",\"userid\":").append(this.userid);
|
||||||
|
if (this.groupid != null) sb.append(",\"groupid\":\"").append(this.groupid).append("\"");
|
||||||
|
if (this.topic != null) sb.append(",\"topic\":\"").append(this.topic).append("\"");
|
||||||
|
if (this.resptopic != null) sb.append(",\"resptopic\":\"").append(this.resptopic).append("\"");
|
||||||
|
if (this.content != null) sb.append(",\"content\":").append(this.format == ConvertType.JSON ? ("\"" + new String(this.content, StandardCharsets.UTF_8) + "\"") : JsonConvert.root().convertTo(this.content));
|
||||||
|
sb.append("}");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static void main(String[] args) throws Throwable {
|
||||||
|
// System.out.println(new MessageRecord(333, ConvertType.JSON, 2, 3, null, "tt", null, "xxx".getBytes()));
|
||||||
|
// }
|
||||||
|
}
|
||||||
84
src/org/redkale/mq/MessageRecordCoder.java
Normal file
84
src/org/redkale/mq/MessageRecordCoder.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import org.redkale.convert.ConvertType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageRecord的MessageCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class MessageRecordCoder implements MessageCoder<MessageRecord> {
|
||||||
|
|
||||||
|
private static final MessageRecordCoder instance = new MessageRecordCoder();
|
||||||
|
|
||||||
|
public static MessageRecordCoder getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encode(MessageRecord data) {
|
||||||
|
if (data == null) return null;
|
||||||
|
byte[] stopics = MessageCoder.getBytes(data.getTopic());
|
||||||
|
byte[] dtopics = MessageCoder.getBytes(data.getResptopic());
|
||||||
|
byte[] groupid = MessageCoder.getBytes(data.getGroupid());
|
||||||
|
int count = 8 + 4 + 4 + 4 + 8 + 4 + 2 + stopics.length + 2 + dtopics.length + 2 + groupid.length + 4 + (data.getContent() == null ? 0 : data.getContent().length);
|
||||||
|
final byte[] bs = new byte[count];
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(bs);
|
||||||
|
buffer.putLong(data.getSeqid());
|
||||||
|
buffer.putInt(data.getVersion());
|
||||||
|
buffer.putInt(data.getFormat() == null ? 0 : data.getFormat().getValue());
|
||||||
|
buffer.putInt(data.getFlag());
|
||||||
|
buffer.putLong(data.getCreatetime());
|
||||||
|
buffer.putInt(data.getUserid());
|
||||||
|
buffer.putChar((char) groupid.length);
|
||||||
|
if (groupid.length > 0) buffer.put(groupid);
|
||||||
|
buffer.putChar((char) stopics.length);
|
||||||
|
if (stopics.length > 0) buffer.put(stopics);
|
||||||
|
buffer.putChar((char) dtopics.length);
|
||||||
|
if (dtopics.length > 0) buffer.put(dtopics);
|
||||||
|
if (data.getContent() == null) {
|
||||||
|
buffer.putInt(0);
|
||||||
|
} else {
|
||||||
|
buffer.putInt(data.getContent().length);
|
||||||
|
buffer.put(data.getContent());
|
||||||
|
}
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MessageRecord decode(byte[] data) {
|
||||||
|
if (data == null) return null;
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||||
|
long seqid = buffer.getLong();
|
||||||
|
int version = buffer.getInt();
|
||||||
|
ConvertType format = ConvertType.find(buffer.getInt());
|
||||||
|
int flag = buffer.getInt();
|
||||||
|
long createtime = buffer.getLong();
|
||||||
|
int userid = buffer.getInt();
|
||||||
|
|
||||||
|
String groupid = MessageCoder.getShortString(buffer);
|
||||||
|
String topic = MessageCoder.getShortString(buffer);
|
||||||
|
String resptopic = MessageCoder.getShortString(buffer);
|
||||||
|
|
||||||
|
byte[] content = null;
|
||||||
|
int contentlen = buffer.getInt();
|
||||||
|
if (contentlen > 0) {
|
||||||
|
content = new byte[contentlen];
|
||||||
|
buffer.get(content);
|
||||||
|
}
|
||||||
|
return new MessageRecord(seqid, version, format, flag,
|
||||||
|
createtime, userid, groupid, topic, resptopic, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
62
src/org/redkale/mq/MessageRespFutureNode.java
Normal file
62
src/org/redkale/mq/MessageRespFutureNode.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQ管理器
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class MessageRespFutureNode implements Runnable {
|
||||||
|
|
||||||
|
protected final long seqid;
|
||||||
|
|
||||||
|
protected final long createtime;
|
||||||
|
|
||||||
|
protected final AtomicLong counter;
|
||||||
|
|
||||||
|
protected final CompletableFuture<MessageRecord> future;
|
||||||
|
|
||||||
|
protected final ConcurrentHashMap<Long, MessageRespFutureNode> respNodes;
|
||||||
|
|
||||||
|
public MessageRespFutureNode(MessageRecord message, ConcurrentHashMap<Long, MessageRespFutureNode> respNodes, AtomicLong counter, CompletableFuture<MessageRecord> future) {
|
||||||
|
this.seqid = message.getSeqid();
|
||||||
|
this.respNodes = respNodes;
|
||||||
|
this.counter = counter;
|
||||||
|
this.future = future;
|
||||||
|
this.createtime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override //超时后被timeoutExecutor调用
|
||||||
|
public void run() { //timeout
|
||||||
|
respNodes.remove(this.seqid);
|
||||||
|
future.completeExceptionally(new TimeoutException());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSeqid() {
|
||||||
|
return seqid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCreatetime() {
|
||||||
|
return createtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtomicLong getCounter() {
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<MessageRecord> getFuture() {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/org/redkale/mq/MessageResponse.java
Normal file
20
src/org/redkale/mq/MessageResponse.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public interface MessageResponse {
|
||||||
|
|
||||||
|
public void finish(MessageRecord message);
|
||||||
|
}
|
||||||
58
src/org/redkale/mq/SncpMessageClient.java
Normal file
58
src/org/redkale/mq/SncpMessageClient.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.mq;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import org.redkale.convert.ConvertType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class SncpMessageClient extends MessageClient {
|
||||||
|
|
||||||
|
protected SncpMessageClient(MessageAgent messageAgent) {
|
||||||
|
super(messageAgent);
|
||||||
|
this.respTopic = messageAgent.generateSncpRespTopic();
|
||||||
|
this.convertType = ConvertType.BSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MessageProducers getProducer() {
|
||||||
|
return messageAgent.getSncpProducer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRespTopic() {
|
||||||
|
return this.respTopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
//只发送消息,不需要响应
|
||||||
|
public final void produceMessage(MessageRecord message) {
|
||||||
|
produceMessage(message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//只发送消息,不需要响应
|
||||||
|
public final void produceMessage(MessageRecord message, AtomicLong counter) {
|
||||||
|
sendMessage(message, false, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送消息,需要响应
|
||||||
|
public final CompletableFuture<MessageRecord> sendMessage(MessageRecord message) {
|
||||||
|
return sendMessage(message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送消息,需要响应
|
||||||
|
public final CompletableFuture<MessageRecord> sendMessage(MessageRecord message, AtomicLong counter) {
|
||||||
|
return sendMessage(message, true, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
107
src/org/redkale/mq/SncpMessageProcessor.java
Normal file
107
src/org/redkale/mq/SncpMessageProcessor.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.logging.*;
|
||||||
|
import org.redkale.boot.NodeSncpServer;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.service.Service;
|
||||||
|
import org.redkale.util.ThreadHashExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class SncpMessageProcessor implements MessageProcessor {
|
||||||
|
|
||||||
|
protected final Logger logger;
|
||||||
|
|
||||||
|
protected final MessageProducers producer;
|
||||||
|
|
||||||
|
protected final NodeSncpServer server;
|
||||||
|
|
||||||
|
protected final ThreadHashExecutor workExecutor;
|
||||||
|
|
||||||
|
protected final Service service;
|
||||||
|
|
||||||
|
protected final SncpServlet servlet;
|
||||||
|
|
||||||
|
protected CountDownLatch cdl;
|
||||||
|
|
||||||
|
protected final Runnable innerCallback = () -> {
|
||||||
|
if (cdl != null) cdl.countDown();
|
||||||
|
};
|
||||||
|
|
||||||
|
public SncpMessageProcessor(Logger logger, ThreadHashExecutor workExecutor, MessageProducers producer, NodeSncpServer server, Service service, SncpServlet servlet) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.producer = producer;
|
||||||
|
this.server = server;
|
||||||
|
this.service = service;
|
||||||
|
this.servlet = servlet;
|
||||||
|
this.workExecutor = workExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(final int size) {
|
||||||
|
if (this.workExecutor != null) this.cdl = new CountDownLatch(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(final MessageRecord message, final Runnable callback) {
|
||||||
|
if (this.workExecutor == null) {
|
||||||
|
execute(message, innerCallback);
|
||||||
|
} else {
|
||||||
|
this.workExecutor.execute(message.hash(), () -> execute(message, innerCallback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execute(final MessageRecord message, final Runnable callback) {
|
||||||
|
SncpMessageResponse response = null;
|
||||||
|
try {
|
||||||
|
SncpContext context = server.getSncpServer().getContext();
|
||||||
|
SncpMessageRequest request = new SncpMessageRequest(context, message);
|
||||||
|
response = new SncpMessageResponse(context, request, callback, null, producer.getProducer(message));
|
||||||
|
servlet.execute(request, response);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
if (response != null) response.finish(SncpResponse.RETCODE_ILLSERVICEID, null);
|
||||||
|
logger.log(Level.SEVERE, SncpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commit() {
|
||||||
|
if (this.cdl != null) {
|
||||||
|
try {
|
||||||
|
this.cdl.await(30, TimeUnit.SECONDS);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
this.cdl = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageProducers getProducer() {
|
||||||
|
return producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeSncpServer getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Service getService() {
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SncpServlet getServlet() {
|
||||||
|
return servlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
31
src/org/redkale/mq/SncpMessageRequest.java
Normal file
31
src/org/redkale/mq/SncpMessageRequest.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.mq;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class SncpMessageRequest extends SncpRequest {
|
||||||
|
|
||||||
|
protected MessageRecord message;
|
||||||
|
|
||||||
|
@SuppressWarnings("OverridableMethodCallInConstructor")
|
||||||
|
public SncpMessageRequest(SncpContext context, MessageRecord message) {
|
||||||
|
super(context, null);
|
||||||
|
this.message = message;
|
||||||
|
readHeader(ByteBuffer.wrap(message.getContent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
61
src/org/redkale/mq/SncpMessageResponse.java
Normal file
61
src/org/redkale/mq/SncpMessageResponse.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.mq;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import org.redkale.convert.ConvertType;
|
||||||
|
import org.redkale.convert.bson.BsonWriter;
|
||||||
|
import org.redkale.net.Response;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
import static org.redkale.net.sncp.SncpRequest.HEADER_SIZE;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public class SncpMessageResponse extends SncpResponse {
|
||||||
|
|
||||||
|
protected MessageRecord message;
|
||||||
|
|
||||||
|
protected MessageProducer producer;
|
||||||
|
|
||||||
|
protected Runnable callback;
|
||||||
|
|
||||||
|
public SncpMessageResponse(SncpContext context, SncpMessageRequest request, Runnable callback, ObjectPool<Response> responsePool, MessageProducer producer) {
|
||||||
|
super(context, request, responsePool);
|
||||||
|
this.message = request.message;
|
||||||
|
this.callback = callback;
|
||||||
|
this.producer = producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SncpMessageResponse(SncpContext context, MessageRecord message, Runnable callback, ObjectPool<Response> responsePool, MessageProducer producer) {
|
||||||
|
super(context, new SncpMessageRequest(context, message), responsePool);
|
||||||
|
this.message = message;
|
||||||
|
this.callback = callback;
|
||||||
|
this.producer = producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(final int retcode, final BsonWriter out) {
|
||||||
|
if (callback != null) callback.run();
|
||||||
|
if (out == null) {
|
||||||
|
final byte[] result = new byte[SncpRequest.HEADER_SIZE];
|
||||||
|
fillHeader(ByteBuffer.wrap(result), 0, retcode);
|
||||||
|
producer.apply(new MessageRecord(message.getSeqid(), ConvertType.BSON, message.getResptopic(), null, (byte[]) null));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int respBodyLength = out.count(); //body总长度
|
||||||
|
final byte[] result = out.toArray();
|
||||||
|
fillHeader(ByteBuffer.wrap(result), respBodyLength - HEADER_SIZE, retcode);
|
||||||
|
producer.apply(new MessageRecord(message.getSeqid(), ConvertType.BSON, message.getResptopic(), null, result));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.net;
|
package org.redkale.net;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
@@ -14,7 +14,7 @@ import java.util.concurrent.*;
|
|||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import org.redkale.util.ObjectPool;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -23,49 +23,57 @@ import org.redkale.util.ObjectPool;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public abstract class AsyncConnection implements ReadableByteChannel, WritableByteChannel, AutoCloseable {
|
public abstract class AsyncConnection implements AutoCloseable {
|
||||||
|
|
||||||
protected SSLContext sslContext;
|
private SSLContext sslContext;
|
||||||
|
|
||||||
protected Map<String, Object> attributes; //用于存储绑定在Connection上的对象集合
|
private Map<String, Object> attributes; //用于存储绑定在Connection上的对象集合
|
||||||
|
|
||||||
protected Object subobject; //用于存储绑定在Connection上的对象, 同attributes, 只绑定单个对象时尽量使用subobject而非attributes
|
private Object subobject; //用于存储绑定在Connection上的对象, 同attributes, 只绑定单个对象时尽量使用subobject而非attributes
|
||||||
|
|
||||||
protected volatile long readtime;
|
protected volatile long readtime;
|
||||||
|
|
||||||
protected volatile long writetime;
|
protected volatile long writetime;
|
||||||
|
|
||||||
protected final Supplier<ByteBuffer> bufferSupplier;
|
private final Supplier<ByteBuffer> bufferSupplier;
|
||||||
|
|
||||||
protected final Consumer<ByteBuffer> bufferConsumer;
|
private final Consumer<ByteBuffer> bufferConsumer;
|
||||||
|
|
||||||
protected ByteBuffer readBuffer;
|
private ByteBuffer readBuffer;
|
||||||
|
|
||||||
//在线数
|
//在线数
|
||||||
protected AtomicLong livingCounter;
|
private AtomicLong livingCounter;
|
||||||
|
|
||||||
//关闭数
|
//关闭数
|
||||||
protected AtomicLong closedCounter;
|
private AtomicLong closedCounter;
|
||||||
|
|
||||||
protected Consumer<AsyncConnection> beforeCloseListener;
|
private Consumer<AsyncConnection> beforeCloseListener;
|
||||||
|
|
||||||
//关联的事件数, 小于1表示没有事件
|
//关联的事件数, 小于1表示没有事件
|
||||||
protected final AtomicInteger eventing = new AtomicInteger();
|
private final AtomicInteger eventing = new AtomicInteger();
|
||||||
|
|
||||||
protected AsyncConnection(Context context) {
|
protected AsyncConnection(ObjectPool<ByteBuffer> bufferPool, SSLContext sslContext,
|
||||||
this(context.getBufferSupplier(), context.getBufferConsumer(), context.getSSLContext());
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
this(bufferPool, bufferPool, sslContext, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AsyncConnection(ObjectPool<ByteBuffer> bufferPool, SSLContext sslContext) {
|
protected AsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer, SSLContext sslContext,
|
||||||
this(bufferPool, bufferPool, sslContext);
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
}
|
|
||||||
|
|
||||||
protected AsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer, SSLContext sslContext) {
|
|
||||||
Objects.requireNonNull(bufferSupplier);
|
Objects.requireNonNull(bufferSupplier);
|
||||||
Objects.requireNonNull(bufferConsumer);
|
Objects.requireNonNull(bufferConsumer);
|
||||||
this.bufferSupplier = bufferSupplier;
|
this.bufferSupplier = bufferSupplier;
|
||||||
this.bufferConsumer = bufferConsumer;
|
this.bufferConsumer = bufferConsumer;
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
|
this.livingCounter = livingCounter;
|
||||||
|
this.closedCounter = closedCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Supplier<ByteBuffer> getBufferSupplier() {
|
||||||
|
return this.bufferSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<ByteBuffer> getBufferConsumer() {
|
||||||
|
return this.bufferConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final long getLastReadTime() {
|
public final long getLastReadTime() {
|
||||||
@@ -84,7 +92,6 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
|||||||
return eventing.decrementAndGet();
|
return eventing.decrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract boolean isOpen();
|
public abstract boolean isOpen();
|
||||||
|
|
||||||
public abstract boolean isTCP();
|
public abstract boolean isTCP();
|
||||||
@@ -109,15 +116,11 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
|||||||
|
|
||||||
public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds);
|
public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds);
|
||||||
|
|
||||||
@Override
|
public abstract ReadableByteChannel readableByteChannel();
|
||||||
public abstract int read(ByteBuffer dst) throws IOException;
|
|
||||||
|
|
||||||
public abstract void read(CompletionHandler<Integer, ByteBuffer> handler);
|
public abstract void read(CompletionHandler<Integer, ByteBuffer> handler);
|
||||||
|
|
||||||
public abstract void read(long timeout, TimeUnit unit, CompletionHandler<Integer, ByteBuffer> handler);
|
public abstract WritableByteChannel writableByteChannel();
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract int write(ByteBuffer src) throws IOException;
|
|
||||||
|
|
||||||
public abstract <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler);
|
||||||
|
|
||||||
@@ -127,9 +130,9 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
|||||||
|
|
||||||
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
||||||
|
|
||||||
public void setReadBuffer(Buffer buffer) {
|
public void setReadBuffer(ByteBuffer buffer) {
|
||||||
if (this.readBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadBuffer");
|
if (this.readBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadBuffer");
|
||||||
this.readBuffer = (ByteBuffer) buffer;
|
this.readBuffer = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer pollReadBuffer() {
|
public ByteBuffer pollReadBuffer() {
|
||||||
@@ -141,15 +144,16 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
|||||||
return bufferSupplier.get();
|
return bufferSupplier.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerBuffer(Buffer buffer) {
|
public void offerBuffer(ByteBuffer buffer) {
|
||||||
if (buffer == null) return;
|
if (buffer == null) return;
|
||||||
bufferConsumer.accept((ByteBuffer) buffer);
|
bufferConsumer.accept(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerBuffer(Buffer... buffers) {
|
public void offerBuffer(ByteBuffer... buffers) {
|
||||||
if (buffers == null) return;
|
if (buffers == null) return;
|
||||||
for (Buffer buffer : buffers) {
|
Consumer<ByteBuffer> consumer = this.bufferConsumer;
|
||||||
bufferConsumer.accept((ByteBuffer) buffer);
|
for (ByteBuffer buffer : buffers) {
|
||||||
|
consumer.accept(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +190,12 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.readBuffer != null) {
|
if (this.readBuffer != null) {
|
||||||
bufferConsumer.accept(this.readBuffer);
|
Consumer<ByteBuffer> consumer = this.bufferConsumer;
|
||||||
|
// Thread thread = Thread.currentThread();
|
||||||
|
// if (thread instanceof IOThread) {
|
||||||
|
// consumer = ((IOThread) thread).getBufferPool();
|
||||||
|
// }
|
||||||
|
consumer.accept(this.readBuffer);
|
||||||
}
|
}
|
||||||
if (attributes == null) return;
|
if (attributes == null) return;
|
||||||
try {
|
try {
|
||||||
@@ -245,22 +254,6 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
|||||||
return createTCP(bufferPool, group, null, address, readTimeoutSeconds, writeTimeoutSeconds);
|
return createTCP(bufferPool, group, null, address, readTimeoutSeconds, writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建TCP协议客户端连接
|
|
||||||
*
|
|
||||||
* @param context Context
|
|
||||||
* @param address 连接点子
|
|
||||||
* @param group 连接AsynchronousChannelGroup
|
|
||||||
* @param readTimeoutSeconds 读取超时秒数
|
|
||||||
* @param writeTimeoutSeconds 写入超时秒数
|
|
||||||
*
|
|
||||||
* @return 连接CompletableFuture
|
|
||||||
*/
|
|
||||||
public static CompletableFuture<AsyncConnection> createTCP(final Context context, final AsynchronousChannelGroup group,
|
|
||||||
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
|
||||||
return createTCP(context.getBufferSupplier(), context.getBufferConsumer(), group, context.getSSLContext(), address, readTimeoutSeconds, writeTimeoutSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建TCP协议客户端连接
|
* 创建TCP协议客户端连接
|
||||||
*
|
*
|
||||||
@@ -371,35 +364,6 @@ public abstract class AsyncConnection implements ReadableByteChannel, WritableBy
|
|||||||
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch) {
|
|
||||||
return create(context, ch, (SocketAddress) null, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
|
||||||
final SocketAddress addr0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
|
||||||
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
|
||||||
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
|
||||||
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
|
||||||
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
|
||||||
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
|
||||||
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch) {
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch) {
|
||||||
return create(bufferPool, ch, null, 0, 0);
|
return create(bufferPool, ch, null, 0, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,8 @@
|
|||||||
package org.redkale.net;
|
package org.redkale.net;
|
||||||
|
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.*;
|
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import org.redkale.convert.bson.*;
|
import org.redkale.convert.bson.*;
|
||||||
@@ -39,12 +36,6 @@ public class Context {
|
|||||||
//ByteBuffer的容量,默认8K
|
//ByteBuffer的容量,默认8K
|
||||||
protected final int bufferCapacity;
|
protected final int bufferCapacity;
|
||||||
|
|
||||||
//ByteBuffer对象池
|
|
||||||
protected final ObjectPool<ByteBuffer> bufferPool;
|
|
||||||
|
|
||||||
//Response对象池
|
|
||||||
protected final ObjectPool<Response> responsePool;
|
|
||||||
|
|
||||||
//服务的根Servlet
|
//服务的根Servlet
|
||||||
protected final PrepareServlet prepare;
|
protected final PrepareServlet prepare;
|
||||||
|
|
||||||
@@ -83,22 +74,18 @@ public class Context {
|
|||||||
|
|
||||||
public Context(ContextConfig config) {
|
public Context(ContextConfig config) {
|
||||||
this(config.serverStartTime, config.logger, config.executor, config.sslContext,
|
this(config.serverStartTime, config.logger, config.executor, config.sslContext,
|
||||||
config.bufferCapacity, config.bufferPool, config.responsePool, config.maxconns, config.maxbody,
|
config.bufferCapacity, config.maxconns, config.maxbody, config.charset, config.address, config.resourceFactory,
|
||||||
config.charset, config.address, config.resourceFactory, config.prepare,
|
config.prepare, config.aliveTimeoutSeconds, config.readTimeoutSeconds, config.writeTimeoutSeconds);
|
||||||
config.aliveTimeoutSeconds, config.readTimeoutSeconds, config.writeTimeoutSeconds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Context(long serverStartTime, Logger logger, ThreadPoolExecutor executor, SSLContext sslContext,
|
public Context(long serverStartTime, Logger logger, ThreadPoolExecutor executor, SSLContext sslContext,
|
||||||
int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool, final int maxconns,
|
int bufferCapacity, final int maxconns, final int maxbody, Charset charset, InetSocketAddress address,
|
||||||
final int maxbody, Charset charset, InetSocketAddress address, ResourceFactory resourceFactory,
|
ResourceFactory resourceFactory, PrepareServlet prepare, int aliveTimeoutSeconds, int readTimeoutSeconds, int writeTimeoutSeconds) {
|
||||||
final PrepareServlet prepare, final int aliveTimeoutSeconds, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
|
||||||
this.serverStartTime = serverStartTime;
|
this.serverStartTime = serverStartTime;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
this.bufferCapacity = bufferCapacity;
|
this.bufferCapacity = bufferCapacity;
|
||||||
this.bufferPool = bufferPool;
|
|
||||||
this.responsePool = responsePool;
|
|
||||||
this.maxconns = maxconns;
|
this.maxconns = maxconns;
|
||||||
this.maxbody = maxbody;
|
this.maxbody = maxbody;
|
||||||
this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset;
|
this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset;
|
||||||
@@ -148,40 +135,18 @@ public class Context {
|
|||||||
executor.execute(r);
|
executor.execute(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCorePoolSize() {
|
||||||
|
return executor.getCorePoolSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadFactory getThreadFactory() {
|
||||||
|
return executor.getThreadFactory();
|
||||||
|
}
|
||||||
|
|
||||||
public int getBufferCapacity() {
|
public int getBufferCapacity() {
|
||||||
return bufferCapacity;
|
return bufferCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Supplier<ByteBuffer> getBufferSupplier() {
|
|
||||||
return bufferPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Consumer<ByteBuffer> getBufferConsumer() {
|
|
||||||
return bufferPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer pollBuffer() {
|
|
||||||
return bufferPool.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void offerBuffer(ByteBuffer buffer) {
|
|
||||||
bufferPool.accept(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void offerBuffer(ByteBuffer... buffers) {
|
|
||||||
if (buffers == null) return;
|
|
||||||
for (ByteBuffer buffer : buffers) {
|
|
||||||
bufferPool.accept(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void offerBuffer(Collection<ByteBuffer> buffers) {
|
|
||||||
if (buffers == null) return;
|
|
||||||
for (ByteBuffer buffer : buffers) {
|
|
||||||
bufferPool.accept(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Logger getLogger() {
|
public Logger getLogger() {
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
@@ -220,12 +185,6 @@ public class Context {
|
|||||||
//ByteBuffer的容量,默认8K
|
//ByteBuffer的容量,默认8K
|
||||||
public int bufferCapacity;
|
public int bufferCapacity;
|
||||||
|
|
||||||
//ByteBuffer对象池
|
|
||||||
public ObjectPool<ByteBuffer> bufferPool;
|
|
||||||
|
|
||||||
//Response对象池
|
|
||||||
public ObjectPool<Response> responsePool;
|
|
||||||
|
|
||||||
//服务的根Servlet
|
//服务的根Servlet
|
||||||
public PrepareServlet prepare;
|
public PrepareServlet prepare;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ package org.redkale.net;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
@@ -28,12 +27,15 @@ public class PrepareRunner implements Runnable {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
|
private final ObjectPool<Response> responsePool;
|
||||||
|
|
||||||
private ByteBuffer data;
|
private ByteBuffer data;
|
||||||
|
|
||||||
private Response response;
|
private Response response;
|
||||||
|
|
||||||
public PrepareRunner(Context context, AsyncConnection channel, ByteBuffer data, Response response) {
|
public PrepareRunner(Context context, ObjectPool<Response> responsePool, AsyncConnection channel, ByteBuffer data, Response response) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.responsePool = responsePool;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.response = response;
|
this.response = response;
|
||||||
@@ -41,8 +43,6 @@ public class PrepareRunner implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final boolean keepalive = response != null;
|
|
||||||
final ObjectPool<? extends Response> responsePool = context.responsePool;
|
|
||||||
if (data != null) { //BIO模式的UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了
|
if (data != null) { //BIO模式的UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了
|
||||||
if (response == null) response = responsePool.get();
|
if (response == null) response = responsePool.get();
|
||||||
try {
|
try {
|
||||||
@@ -56,12 +56,12 @@ public class PrepareRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
if (response == null) response = responsePool.get();
|
if (response == null) response = responsePool.get();
|
||||||
try {
|
try {
|
||||||
channel.read(keepalive ? context.getAliveTimeoutSeconds() : context.getReadTimeoutSeconds(), TimeUnit.SECONDS,
|
channel.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
new CompletionHandler<Integer, ByteBuffer>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer count, ByteBuffer buffer) {
|
public void completed(Integer count, ByteBuffer buffer) {
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
response.request.offerReadBuffer(buffer);
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(buffer);
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
@@ -85,7 +85,8 @@ public class PrepareRunner implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer buffer) {
|
public void failed(Throwable exc, ByteBuffer buffer) {
|
||||||
response.request.offerReadBuffer(buffer);
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(buffer);
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
@@ -98,7 +99,7 @@ public class PrepareRunner implements Runnable {
|
|||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
if (te != null && context.logger.isLoggable(Level.FINEST)) {
|
if (context.logger.isLoggable(Level.FINEST)) {
|
||||||
context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te);
|
context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +118,8 @@ public class PrepareRunner implements Runnable {
|
|||||||
if (buffer.hasRemaining()) {
|
if (buffer.hasRemaining()) {
|
||||||
request.setMoredata(buffer);
|
request.setMoredata(buffer);
|
||||||
} else {
|
} else {
|
||||||
response.request.offerReadBuffer(buffer);
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(buffer);
|
||||||
}
|
}
|
||||||
preparer.prepare(request, response);
|
preparer.prepare(request, response);
|
||||||
} else {
|
} else {
|
||||||
@@ -138,7 +140,8 @@ public class PrepareRunner implements Runnable {
|
|||||||
if (attachment.hasRemaining()) {
|
if (attachment.hasRemaining()) {
|
||||||
request.setMoredata(attachment);
|
request.setMoredata(attachment);
|
||||||
} else {
|
} else {
|
||||||
response.request.offerReadBuffer(attachment);
|
attachment.clear();
|
||||||
|
channel.setReadBuffer(attachment);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
preparer.prepare(request, response);
|
preparer.prepare(request, response);
|
||||||
@@ -152,7 +155,8 @@ public class PrepareRunner implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
preparer.illRequestCounter.incrementAndGet();
|
preparer.illRequestCounter.incrementAndGet();
|
||||||
response.request.offerReadBuffer(attachment);
|
attachment.clear();
|
||||||
|
channel.setReadBuffer(attachment);
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, force to close channel ", exc);
|
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, force to close channel ", exc);
|
||||||
}
|
}
|
||||||
@@ -165,7 +169,7 @@ public class PrepareRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Response pollResponse() {
|
protected Response pollResponse() {
|
||||||
return context.responsePool.get();
|
return responsePool.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Request pollRequest(Response response) {
|
protected Request pollRequest(Response response) {
|
||||||
@@ -176,19 +180,4 @@ public class PrepareRunner implements Runnable {
|
|||||||
return response.removeChannel();
|
return response.removeChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer(Request request) {
|
|
||||||
return request.pollReadBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer(Response response) {
|
|
||||||
return response.request.pollReadBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(Request request, ByteBuffer buffer) {
|
|
||||||
request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(Response response, ByteBuffer buffer) {
|
|
||||||
response.request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public abstract class ProtocolServer {
|
|||||||
|
|
||||||
public abstract <T> void setOption(SocketOption<T> name, T value) throws IOException;
|
public abstract <T> void setOption(SocketOption<T> name, T value) throws IOException;
|
||||||
|
|
||||||
public abstract void accept() throws IOException;
|
public abstract void accept(Server server) throws IOException;
|
||||||
|
|
||||||
public abstract void close() throws IOException;
|
public abstract void close() throws IOException;
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ public abstract class ProtocolServer {
|
|||||||
} else if ("aio".equalsIgnoreCase(netimpl)) {
|
} else if ("aio".equalsIgnoreCase(netimpl)) {
|
||||||
return new TcpAioProtocolServer(context);
|
return new TcpAioProtocolServer(context);
|
||||||
} else if ("nio".equalsIgnoreCase(netimpl)) {
|
} else if ("nio".equalsIgnoreCase(netimpl)) {
|
||||||
return null;// return new TcpNioProtocolServer(context);
|
return new TcpNioProtocolServer(context);
|
||||||
}
|
}
|
||||||
} else if ("UDP".equalsIgnoreCase(protocol)) {
|
} else if ("UDP".equalsIgnoreCase(protocol)) {
|
||||||
if (netimpl == null || netimpl.isEmpty()) {
|
if (netimpl == null || netimpl.isEmpty()) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.redkale.convert.bson.BsonConvert;
|
import org.redkale.convert.bson.BsonConvert;
|
||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议请求对象
|
* 协议请求对象
|
||||||
@@ -23,6 +24,8 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected final C context;
|
protected final C context;
|
||||||
|
|
||||||
|
protected final ObjectPool<ByteBuffer> bufferPool;
|
||||||
|
|
||||||
protected final BsonConvert bsonConvert;
|
protected final BsonConvert bsonConvert;
|
||||||
|
|
||||||
protected final JsonConvert jsonConvert;
|
protected final JsonConvert jsonConvert;
|
||||||
@@ -37,8 +40,6 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected AsyncConnection channel;
|
protected AsyncConnection channel;
|
||||||
|
|
||||||
protected ByteBuffer readBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留;
|
* properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留;
|
||||||
* properties 通常存放需要永久绑定在request里的一些对象
|
* properties 通常存放需要永久绑定在request里的一些对象
|
||||||
@@ -47,9 +48,9 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected final Map<String, Object> attributes = new HashMap<>();
|
protected final Map<String, Object> attributes = new HashMap<>();
|
||||||
|
|
||||||
protected Request(C context) {
|
protected Request(C context, ObjectPool<ByteBuffer> bufferPool) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.readBuffer = context.pollBuffer();
|
this.bufferPool = bufferPool;
|
||||||
this.bsonConvert = context.getBsonConvert();
|
this.bsonConvert = context.getBsonConvert();
|
||||||
this.jsonConvert = context.getJsonConvert();
|
this.jsonConvert = context.getJsonConvert();
|
||||||
}
|
}
|
||||||
@@ -64,23 +65,6 @@ public abstract class Request<C extends Context> {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.readBuffer;
|
|
||||||
this.readBuffer = null;
|
|
||||||
if (buffer == null) buffer = context.pollBuffer();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(ByteBuffer buffer) {
|
|
||||||
if (buffer == null) return;
|
|
||||||
if (this.readBuffer == null) {
|
|
||||||
buffer.clear();
|
|
||||||
this.readBuffer = buffer;
|
|
||||||
} else {
|
|
||||||
context.offerBuffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议响应对象
|
* 协议响应对象
|
||||||
@@ -26,14 +27,12 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
protected final C context;
|
protected final C context;
|
||||||
|
|
||||||
|
protected final ObjectPool<Response> responsePool; //虚拟构建的Response可能不存在responsePool
|
||||||
|
|
||||||
protected final R request;
|
protected final R request;
|
||||||
|
|
||||||
protected AsyncConnection channel;
|
protected AsyncConnection channel;
|
||||||
|
|
||||||
protected ByteBuffer writeHeadBuffer;
|
|
||||||
|
|
||||||
protected ByteBuffer writeBodyBuffer;
|
|
||||||
|
|
||||||
private volatile boolean inited = true;
|
private volatile boolean inited = true;
|
||||||
|
|
||||||
protected Object output; //输出的结果对象
|
protected Object output; //输出的结果对象
|
||||||
@@ -44,8 +43,6 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
protected Servlet<C, R, ? extends Response<C, R>> servlet;
|
protected Servlet<C, R, ? extends Response<C, R>> servlet;
|
||||||
|
|
||||||
private Supplier<ByteBuffer> bodyBufferSupplier;
|
|
||||||
|
|
||||||
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
|
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -53,31 +50,21 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
if (attachment.hasRemaining()) {
|
if (attachment.hasRemaining()) {
|
||||||
channel.write(attachment, attachment, this);
|
channel.write(attachment, attachment, this);
|
||||||
} else {
|
} else {
|
||||||
offerResponseBuffer(attachment);
|
channel.offerBuffer(attachment);
|
||||||
|
ByteBuffer data = request.removeMoredata();
|
||||||
|
final boolean more = data != null && request.keepAlive;
|
||||||
|
request.more = more;
|
||||||
finish();
|
finish();
|
||||||
|
if (more) new PrepareRunner(context, responsePool, request.channel, null, Response.this).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerResponseBuffer(attachment);
|
channel.offerBuffer(attachment);
|
||||||
finish(true);
|
finish(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void offerResponseBuffer(ByteBuffer attachment) {
|
|
||||||
if (writeHeadBuffer == null) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachment)) {
|
|
||||||
writeHeadBuffer = attachment;
|
|
||||||
}
|
|
||||||
} else if (writeBodyBuffer == null) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachment)) {
|
|
||||||
writeBodyBuffer = attachment;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
context.offerBuffer(attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
|
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
|
||||||
@@ -94,70 +81,37 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
channel.write(attachments, index, attachments.length - index, attachments, this);
|
channel.write(attachments, index, attachments.length - index, attachments, this);
|
||||||
} else {
|
} else {
|
||||||
offerResponseBuffer(attachments);
|
for (ByteBuffer attachment : attachments) {
|
||||||
|
channel.offerBuffer(attachment);
|
||||||
|
}
|
||||||
|
ByteBuffer data = request.removeMoredata();
|
||||||
|
final boolean more = data != null && request.keepAlive;
|
||||||
|
request.more = more;
|
||||||
finish();
|
finish();
|
||||||
|
if (more) new PrepareRunner(context, responsePool, request.channel, null, Response.this).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, final ByteBuffer[] attachments) {
|
public void failed(Throwable exc, final ByteBuffer[] attachments) {
|
||||||
offerResponseBuffer(attachments);
|
for (ByteBuffer attachment : attachments) {
|
||||||
|
channel.offerBuffer(attachment);
|
||||||
|
}
|
||||||
finish(true);
|
finish(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void offerResponseBuffer(ByteBuffer[] attachments) {
|
|
||||||
int start = 0;
|
|
||||||
if (writeHeadBuffer == null && attachments.length > start) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachments[start])) {
|
|
||||||
writeHeadBuffer = attachments[start];
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (writeBodyBuffer == null && attachments.length > start) {
|
|
||||||
if (context.bufferPool.getRecyclerPredicate().test(attachments[start])) {
|
|
||||||
writeBodyBuffer = attachments[start];
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = start; i < attachments.length; i++) {
|
|
||||||
context.offerBuffer(attachments[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
protected Response(C context, final R request) {
|
protected Response(C context, final R request, ObjectPool<Response> responsePool) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.request = request;
|
this.request = request;
|
||||||
this.writeHeadBuffer = context.pollBuffer();
|
this.responsePool = responsePool;
|
||||||
this.writeBodyBuffer = context.pollBuffer();
|
|
||||||
this.bodyBufferSupplier = () -> {
|
|
||||||
ByteBuffer buffer = writeBodyBuffer;
|
|
||||||
if (buffer == null) return context.pollBuffer();
|
|
||||||
writeBodyBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer pollWriteReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.writeHeadBuffer;
|
|
||||||
this.writeHeadBuffer = null;
|
|
||||||
if (buffer == null) buffer = context.pollBuffer();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer pollWriteBodyBuffer() {
|
|
||||||
ByteBuffer buffer = this.writeBodyBuffer;
|
|
||||||
this.writeBodyBuffer = null;
|
|
||||||
if (buffer == null) buffer = context.pollBuffer();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Supplier<ByteBuffer> getBodyBufferSupplier() {
|
|
||||||
return bodyBufferSupplier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void offerBuffer(ByteBuffer... buffers) {
|
protected void offerBuffer(ByteBuffer... buffers) {
|
||||||
context.offerBuffer(buffers);
|
for (ByteBuffer buffer : buffers) {
|
||||||
|
channel.offerBuffer(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AsyncConnection removeChannel() {
|
protected AsyncConnection removeChannel() {
|
||||||
@@ -257,19 +211,19 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
AsyncConnection conn = removeChannel();
|
AsyncConnection conn = removeChannel();
|
||||||
this.recycle();
|
this.recycle();
|
||||||
this.prepare();
|
this.prepare();
|
||||||
new PrepareRunner(context, conn, null, this).run();
|
new PrepareRunner(context, this.responsePool, conn, null, this).run();
|
||||||
} else {
|
} else {
|
||||||
channel.dispose();
|
channel.dispose();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.context.responsePool.accept(this);
|
this.responsePool.accept(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(final byte[] bs) {
|
public void finish(final byte[] bs) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
if (this.context.bufferCapacity == bs.length) {
|
if (this.context.bufferCapacity == bs.length) {
|
||||||
ByteBuffer buffer = this.context.pollBuffer();
|
ByteBuffer buffer = channel.getBufferSupplier().get();
|
||||||
buffer.put(bs);
|
buffer.put(bs);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
this.finish(buffer);
|
this.finish(buffer);
|
||||||
@@ -280,33 +234,33 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
public void finish(ByteBuffer buffer) {
|
public void finish(ByteBuffer buffer) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
ByteBuffer data = this.request.removeMoredata();
|
|
||||||
final AsyncConnection conn = this.channel;
|
final AsyncConnection conn = this.channel;
|
||||||
final boolean more = data != null && this.request.keepAlive;
|
// ByteBuffer data = this.request.removeMoredata();
|
||||||
this.request.more = more;
|
// final boolean more = data != null && this.request.keepAlive;
|
||||||
|
// this.request.more = more;
|
||||||
conn.write(buffer, buffer, finishHandler);
|
conn.write(buffer, buffer, finishHandler);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(boolean kill, ByteBuffer buffer) {
|
public void finish(boolean kill, ByteBuffer buffer) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
if (kill) refuseAlive();
|
if (kill) refuseAlive();
|
||||||
ByteBuffer data = this.request.removeMoredata();
|
|
||||||
final AsyncConnection conn = this.channel;
|
final AsyncConnection conn = this.channel;
|
||||||
final boolean more = data != null && this.request.keepAlive;
|
// ByteBuffer data = this.request.removeMoredata();
|
||||||
this.request.more = more;
|
// final boolean more = data != null && this.request.keepAlive;
|
||||||
|
// this.request.more = more;
|
||||||
conn.write(buffer, buffer, finishHandler);
|
conn.write(buffer, buffer, finishHandler);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(ByteBuffer... buffers) {
|
public void finish(ByteBuffer... buffers) {
|
||||||
if (!this.inited) return; //避免重复关闭
|
if (!this.inited) return; //避免重复关闭
|
||||||
final AsyncConnection conn = this.channel;
|
final AsyncConnection conn = this.channel;
|
||||||
ByteBuffer data = this.request.removeMoredata();
|
// ByteBuffer data = this.request.removeMoredata();
|
||||||
final boolean more = data != null && this.request.keepAlive;
|
// final boolean more = data != null && this.request.keepAlive;
|
||||||
this.request.more = more;
|
// this.request.more = more;
|
||||||
conn.write(buffers, buffers, finishHandler2);
|
conn.write(buffers, buffers, finishHandler2);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
// if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(boolean kill, ByteBuffer... buffers) {
|
public void finish(boolean kill, ByteBuffer... buffers) {
|
||||||
@@ -317,7 +271,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
final boolean more = data != null && this.request.keepAlive;
|
final boolean more = data != null && this.request.keepAlive;
|
||||||
this.request.more = more;
|
this.request.more = more;
|
||||||
conn.write(buffers, buffers, finishHandler2);
|
conn.write(buffers, buffers, finishHandler2);
|
||||||
if (more) new PrepareRunner(this.context, conn, data, null).run();
|
if (more) new PrepareRunner(this.context, this.responsePool, conn, data, null).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <A> void send(final ByteBuffer buffer, final A attachment, final CompletionHandler<Integer, A> handler) {
|
protected <A> void send(final ByteBuffer buffer, final A attachment, final CompletionHandler<Integer, A> handler) {
|
||||||
@@ -328,14 +282,14 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
if (buffer.hasRemaining()) {
|
if (buffer.hasRemaining()) {
|
||||||
channel.write(buffer, attachment, this);
|
channel.write(buffer, attachment, this);
|
||||||
} else {
|
} else {
|
||||||
context.offerBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
if (handler != null) handler.completed(result, attachment);
|
if (handler != null) handler.completed(result, attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
context.offerBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
if (handler != null) handler.failed(exc, attachment);
|
if (handler != null) handler.failed(exc, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +307,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
context.offerBuffer(buffers[i]);
|
channel.offerBuffer(buffers[i]);
|
||||||
}
|
}
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
channel.write(buffers, attachment, this);
|
channel.write(buffers, attachment, this);
|
||||||
@@ -367,7 +321,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, A attachment) {
|
public void failed(Throwable exc, A attachment) {
|
||||||
for (ByteBuffer buffer : buffers) {
|
for (ByteBuffer buffer : buffers) {
|
||||||
context.offerBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
}
|
}
|
||||||
if (handler != null) handler.failed(exc, attachment);
|
if (handler != null) handler.failed(exc, attachment);
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user