Compare commits
626 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a5e1252ab | ||
|
|
ae5430af42 | ||
|
|
13cf188e25 | ||
|
|
41d3dea1ac | ||
|
|
be816088f5 | ||
|
|
5bef900b76 | ||
|
|
52f61b0f96 | ||
|
|
b5a4646e3b | ||
|
|
d055d5c824 | ||
|
|
f14ef05c88 | ||
|
|
426506324f | ||
|
|
7a5e58a112 | ||
|
|
2e0c58cbea | ||
|
|
9ded3fbb9a | ||
|
|
acbc1032e6 | ||
|
|
d8186b00ba | ||
|
|
767adcbefe | ||
|
|
67df072275 | ||
|
|
dab70af4d4 | ||
|
|
b42826692d | ||
|
|
e2ab4b20c9 | ||
|
|
511ee8a6df | ||
|
|
463269a796 | ||
|
|
2d4b865432 | ||
|
|
1da73429f7 | ||
|
|
e97e6b8262 | ||
|
|
e6bc34d6f8 | ||
|
|
f1c4ac9e67 | ||
|
|
de6c6076e4 | ||
|
|
a36e3d3819 | ||
|
|
043b847f05 | ||
|
|
65bc8192f0 | ||
|
|
71e0b60200 | ||
|
|
99dc7ac189 | ||
|
|
8605c44f14 | ||
|
|
c47e301263 | ||
|
|
6c11ef70d4 | ||
|
|
dddb2397c4 | ||
|
|
f66803b9fd | ||
|
|
0801ce8cad | ||
|
|
5a690912c1 | ||
|
|
a3dddd20c7 | ||
|
|
7200a74b18 | ||
|
|
3847cf47e4 | ||
|
|
0b5a79c1d8 | ||
|
|
685667fd69 | ||
|
|
72e81bd034 | ||
|
|
39eadcd08b | ||
|
|
a46f79a448 | ||
|
|
5ddca03fb6 | ||
|
|
0bd5787992 | ||
|
|
bf88c4da06 | ||
|
|
5e72e782cc | ||
|
|
3c0609fa0e | ||
|
|
945f9f9ef5 | ||
|
|
7c5ac7970e | ||
|
|
68f0c1de29 | ||
|
|
337a2a3038 | ||
|
|
2a5e0e82be | ||
|
|
e0b2120ee5 | ||
|
|
ac5662114a | ||
|
|
f2963e01e0 | ||
|
|
fc54fc3f24 | ||
|
|
41990e7e6a | ||
|
|
01e8649e2a | ||
|
|
71ead72dec | ||
|
|
da600ecf20 | ||
|
|
d46807a585 | ||
|
|
571d13075b | ||
|
|
3ad8eeaae6 | ||
|
|
e540128154 | ||
|
|
c6d83440bb | ||
|
|
97f43a4d8d | ||
|
|
6fddd8b53b | ||
|
|
98a6c3ef79 | ||
|
|
6e70f2043e | ||
|
|
123b94398a | ||
|
|
40c19c1521 | ||
|
|
7089fae390 | ||
|
|
936fe8d1ab | ||
|
|
7780e0090c | ||
|
|
1a7dc97335 | ||
|
|
9af8c863b1 | ||
|
|
2c13224fcc | ||
|
|
5e13575e84 | ||
|
|
eabdc13c53 | ||
|
|
7261bcfadb | ||
|
|
0569e87d4e | ||
|
|
5c339f6f66 | ||
|
|
44eada2697 | ||
|
|
3e0b9daeaf | ||
|
|
3061422d83 | ||
|
|
4280464f85 | ||
|
|
2b1d09b027 | ||
|
|
4f3c2e071a | ||
|
|
d2aacf7b8c | ||
|
|
fbb1fb5a5f | ||
|
|
c9187a78bc | ||
|
|
d984ab2a8f | ||
|
|
ad2a3f0d54 | ||
|
|
e559379294 | ||
|
|
e125aa9885 | ||
|
|
8026ebb215 | ||
|
|
45b04da483 | ||
|
|
0da5867b70 | ||
|
|
b1f51b1c30 | ||
|
|
054253fb90 | ||
|
|
141041dbba | ||
|
|
500545fc93 | ||
|
|
78f1bd90f4 | ||
|
|
f5a04319d5 | ||
|
|
76ce6787d1 | ||
|
|
bd53d4a8ab | ||
|
|
53b11116b9 | ||
|
|
734b1bbbb4 | ||
|
|
f014bffb6c | ||
|
|
f633e72c5f | ||
|
|
b8c85284ab | ||
|
|
a3af6749f6 | ||
|
|
9128dffe35 | ||
|
|
9273f2917e | ||
|
|
4d9d09af8c | ||
|
|
33beb60efe | ||
|
|
129bcf2f78 | ||
|
|
f6c7dde28f | ||
|
|
8fcd33b511 | ||
|
|
66ec26e0ce | ||
|
|
969f7ada82 | ||
|
|
7e37889372 | ||
|
|
c819d4d45b | ||
|
|
6dc59b7abc | ||
|
|
60b24fa1ae | ||
|
|
b784993110 | ||
|
|
cc150a2cc6 | ||
|
|
f6b407aa44 | ||
|
|
a69d813bf5 | ||
|
|
d1eff6144d | ||
|
|
99589387d8 | ||
|
|
e0041235fe | ||
|
|
84b4eee7b5 | ||
|
|
96c0a9bfe4 | ||
|
|
89ad976744 | ||
|
|
0eedc2c180 | ||
|
|
8b3658143a | ||
|
|
6d69ff546b | ||
|
|
9555e3c9b9 | ||
|
|
744634dbdd | ||
|
|
de5ee844c4 | ||
|
|
ae73cee357 | ||
|
|
d1cf9be8d7 | ||
|
|
43ae77ab33 | ||
|
|
182a75cfad | ||
|
|
222dc0edce | ||
|
|
c7a81513fe | ||
|
|
4931c66868 | ||
|
|
fcff1c3a4b | ||
|
|
2005bf7e3b | ||
|
|
cb07a38f04 | ||
|
|
6085cd5eef | ||
|
|
086275c135 | ||
|
|
a449a96ef9 | ||
|
|
bc3209a09c | ||
|
|
63d1ef985d | ||
|
|
24505564c8 | ||
|
|
93a7bd63cf | ||
|
|
0b9b5baa49 | ||
|
|
5c4100e762 | ||
|
|
eb861014c4 | ||
|
|
e62f7ea63d | ||
|
|
d6df2055b2 | ||
|
|
570aac947a | ||
|
|
1fdc33b565 | ||
|
|
af8d0e978e | ||
|
|
c58022a81e | ||
|
|
f4cf828993 | ||
|
|
c4dc0de5fe | ||
|
|
44507a97a6 | ||
|
|
f4a7f1cff6 | ||
|
|
a5fcb45a88 | ||
|
|
bc8b68526d | ||
|
|
180f201dc0 | ||
|
|
9ab315a405 | ||
|
|
27b4742b6d | ||
|
|
702220d18e | ||
|
|
414489da8e | ||
|
|
77057df25d | ||
|
|
2f98cd1ab5 | ||
|
|
8809fe8ec9 | ||
|
|
f9702a9517 | ||
|
|
29e46b9b68 | ||
|
|
f838e35413 | ||
|
|
f3bb77c49b | ||
|
|
12fa033e15 | ||
|
|
f4abfafea2 | ||
|
|
0918af71d2 | ||
|
|
275befa330 | ||
|
|
ab4cd8bcb6 | ||
|
|
36c109b32f | ||
|
|
73a915665d | ||
|
|
bd6d71c94a | ||
|
|
842e93507c | ||
|
|
76df1108d7 | ||
|
|
941d09cde2 | ||
|
|
9dd3e1da07 | ||
|
|
2bf73245ec | ||
|
|
b0ab792f72 | ||
|
|
0df9a940c5 | ||
|
|
fc35fc5abc | ||
|
|
eaa0a99933 | ||
|
|
83bdb97842 | ||
|
|
a71a4d0fed | ||
|
|
835435c220 | ||
|
|
c524ba1797 | ||
|
|
f254b48693 | ||
|
|
922697eb4d | ||
|
|
450e3e3ea2 | ||
|
|
b31f75f4f6 | ||
|
|
1d1f18b046 | ||
|
|
73f942746b | ||
|
|
b6cefe8c2d | ||
|
|
ebc0e4eb41 | ||
|
|
179a7b22ea | ||
|
|
0b87d9a261 | ||
|
|
685a686ead | ||
|
|
568e1cf62d | ||
|
|
1d121bd2ab | ||
|
|
2ca4bdaaec | ||
|
|
878fda30f6 | ||
|
|
abb611382c | ||
|
|
b53510a26f | ||
|
|
2aee84d477 | ||
|
|
0ba2e25f2e | ||
|
|
98e8a7eb05 | ||
|
|
62139efca9 | ||
|
|
2b62cbe455 | ||
|
|
e44602fe3b | ||
|
|
276cb4da92 | ||
|
|
7081f94afc | ||
|
|
2d6cefeb43 | ||
|
|
ea6c703ac6 | ||
|
|
d1f14962fd | ||
|
|
79ca63bf81 | ||
|
|
6421bc2851 | ||
|
|
43f9f50f4c | ||
|
|
5f140a8ce9 | ||
|
|
c0f8cdf902 | ||
|
|
8d66b1b4a7 | ||
|
|
8c7ee4136c | ||
|
|
d9498c9a6c | ||
|
|
08060a8c86 | ||
|
|
2bdf0e4a50 | ||
|
|
eb184df100 | ||
|
|
cf545a731c | ||
|
|
95e18dfd48 | ||
|
|
023a9abdef | ||
|
|
7f3776c224 | ||
|
|
7b15ba33e0 | ||
|
|
a6c105d63d | ||
|
|
10e22b0873 | ||
|
|
53a35e6397 | ||
|
|
b5a3c39f4f | ||
|
|
99381d4842 | ||
|
|
5f2c2a9f2c | ||
|
|
dc3f318949 | ||
|
|
cfae61faea | ||
|
|
dd7626b1a3 | ||
|
|
2171aa1232 | ||
|
|
801ad489d2 | ||
|
|
c88d0b402d | ||
|
|
542bb4353b | ||
|
|
fe1e0a845a | ||
|
|
f320f4c550 | ||
|
|
0ec2bf211a | ||
|
|
b3c54e4db5 | ||
|
|
52838f04a9 | ||
|
|
fa5bd95a2b | ||
|
|
b2e73d378c | ||
|
|
6895b31ad0 | ||
|
|
56637ff7ef | ||
|
|
40b46f9c7f | ||
|
|
0aed26652d | ||
|
|
14238a0203 | ||
|
|
369a70e857 | ||
|
|
6ede9b0f31 | ||
|
|
6c039dc8f4 | ||
|
|
1e69a6755f | ||
|
|
f6c617574c | ||
|
|
2291beb5e7 | ||
|
|
d8e091f888 | ||
|
|
6a42ae7570 | ||
|
|
756e4634d9 | ||
|
|
06773ccdc0 | ||
|
|
0da74be2fa | ||
|
|
1d1b732a74 | ||
|
|
ab90c80785 | ||
|
|
6cd232efd2 | ||
|
|
96e4b8834d | ||
|
|
7ef5ddfd46 | ||
|
|
73a973e0ed | ||
|
|
e0411a94f6 | ||
|
|
054e853074 | ||
|
|
88672b5522 | ||
|
|
0a60b81a98 | ||
|
|
37f8208b1b | ||
|
|
a8b9cc9753 | ||
|
|
a99c7d3454 | ||
|
|
b88987dd98 | ||
|
|
54f4f8e35d | ||
|
|
97670261e6 | ||
|
|
82a2a513f5 | ||
|
|
174a8a2a0c | ||
|
|
92b3d0bbd4 | ||
|
|
24c90b015a | ||
|
|
2742e935cb | ||
|
|
b7770c89b8 | ||
|
|
779a9cca4d | ||
|
|
493c27beb5 | ||
|
|
c68d988d51 | ||
|
|
ceeb924d4d | ||
|
|
4d0a16d35d | ||
|
|
1e60adf5bb | ||
|
|
59b08684a8 | ||
|
|
c326b7ed05 | ||
|
|
d9bf5c8412 | ||
|
|
39d4e6405f | ||
|
|
03bcea30df | ||
|
|
27b67cde0e | ||
|
|
31fca5630b | ||
|
|
3504d735c1 | ||
|
|
74f554fe33 | ||
|
|
b02d4e6731 | ||
|
|
23fd72b116 | ||
|
|
4cd1b10c35 | ||
|
|
71c0763304 | ||
|
|
0ea4ddb5eb | ||
|
|
9bc266ca61 | ||
|
|
b202de4916 | ||
|
|
7d26198e88 | ||
|
|
d98e249fd7 | ||
|
|
7a8b6cac9d | ||
|
|
822ac078b5 | ||
|
|
5e3718af19 | ||
|
|
713fdefb56 | ||
|
|
804e0e27e7 | ||
|
|
2653808f8f | ||
|
|
ba12df2cba | ||
|
|
d2bfa9ab56 | ||
|
|
0fb108bd9b | ||
|
|
145527db38 | ||
|
|
d7c50532cf | ||
|
|
6562ac0a2b | ||
|
|
6f4c9dca48 | ||
|
|
f18ef4f94d | ||
|
|
4786e17243 | ||
|
|
96beb9cef4 | ||
|
|
a59bf92ee7 | ||
|
|
cdc3dbf9ea | ||
|
|
a957a18e32 | ||
|
|
95c53f99e0 | ||
|
|
03ac849451 | ||
|
|
d9946ceb64 | ||
|
|
fda9c30dc4 | ||
|
|
205162ce38 | ||
|
|
f5379df63b | ||
|
|
859e56af4d | ||
|
|
a29cc94f32 | ||
|
|
9e6840f5cb | ||
|
|
52d559ea4a | ||
|
|
95a2b752af | ||
|
|
33da94960c | ||
|
|
dee2002cf3 | ||
|
|
d9a318bba8 | ||
|
|
05925b4f78 | ||
|
|
45fe7cb3e9 | ||
|
|
58271c803b | ||
|
|
88942c61b5 | ||
|
|
88c4824c4f | ||
|
|
62b0be802e | ||
|
|
cdec316312 | ||
|
|
8dcb999444 | ||
|
|
ee460b4196 | ||
|
|
d049b3f9ea | ||
|
|
c244c4edab | ||
|
|
7c533ce8d3 | ||
|
|
f68686114d | ||
|
|
0859dee201 | ||
|
|
46ccd83acc | ||
|
|
d5e44787c0 | ||
|
|
4029b09d81 | ||
|
|
e939241a8c | ||
|
|
cee2c47d9a | ||
|
|
ccceaa2607 | ||
|
|
358a50ecc7 | ||
|
|
6aabae849d | ||
|
|
60cbd9b37d | ||
|
|
df2ee8273d | ||
|
|
8bbee0aff8 | ||
|
|
01ea7f07f5 | ||
|
|
ba928b389b | ||
|
|
39ba0f86f6 | ||
|
|
4d523d1ca4 | ||
|
|
2f60fe795c | ||
|
|
c3560b0ef0 | ||
|
|
804b4dc07d | ||
|
|
bb87774ba9 | ||
|
|
f76ab977d1 | ||
|
|
8003252cf3 | ||
|
|
95c0d0f5cf | ||
|
|
3dcc6ea28f | ||
|
|
85c708b075 | ||
|
|
278c51e26b | ||
|
|
7c0e60d191 | ||
|
|
d1d10f90b9 | ||
|
|
3b601979f4 | ||
|
|
69cc09e76d | ||
|
|
ef28e32e04 | ||
|
|
9954eaf469 | ||
|
|
5ce5f53ed8 | ||
|
|
8e36a7b450 | ||
|
|
f15754386b | ||
|
|
6cc90ac7fe | ||
|
|
3c7f10d657 | ||
|
|
21c84865b9 | ||
|
|
853e823a8d | ||
|
|
6d74355fc0 | ||
|
|
987914e748 | ||
|
|
6e66ee0c99 | ||
|
|
4f7145319f | ||
|
|
ab2656cde6 | ||
|
|
27468d9f0c | ||
|
|
bb8462af2a | ||
|
|
e1df150a37 | ||
|
|
bee4f31323 | ||
|
|
df3a1ef84d | ||
|
|
242b13fff0 | ||
|
|
c3cc9de5b5 | ||
|
|
72e16b88f7 | ||
|
|
f1f0227dca | ||
|
|
63fe26f9cb | ||
|
|
02fcb7b089 | ||
|
|
9db9db4f5e | ||
|
|
e5ce250304 | ||
|
|
a5756c0b4d | ||
|
|
0be3d8a4fa | ||
|
|
017ab1ae84 | ||
|
|
c622e2437d | ||
|
|
3a1f20d438 | ||
|
|
2a9b64e53e | ||
|
|
225745a282 | ||
|
|
83680c46e8 | ||
|
|
7484b80fb2 | ||
|
|
77674ac8d2 | ||
|
|
564067602f | ||
|
|
26778c58c9 | ||
|
|
77cd24fa42 | ||
|
|
4feea0e784 | ||
|
|
681faa415f | ||
|
|
3b54484832 | ||
|
|
fa2513d934 | ||
|
|
5e2be5e926 | ||
|
|
4c071b0a1d | ||
|
|
9e7949d9eb | ||
|
|
29843a9812 | ||
|
|
48a08f27a7 | ||
|
|
4f1a0849ec | ||
|
|
6676c3fd37 | ||
|
|
6daa45ff05 | ||
|
|
28f95a89df | ||
|
|
44d11dae34 | ||
|
|
a1b39ba99b | ||
|
|
abcfb8f10c | ||
|
|
33f49c7632 | ||
|
|
d800a33ded | ||
|
|
f587e13bdc | ||
|
|
f9f2e080da | ||
|
|
027fa3a18b | ||
|
|
d9f50d63f0 | ||
|
|
181486c348 | ||
|
|
74adfdfc99 | ||
|
|
c3783eb041 | ||
|
|
77451561e6 | ||
|
|
59d30b05f2 | ||
|
|
2fcf0bb644 | ||
|
|
71ab9c9728 | ||
|
|
09165127e3 | ||
|
|
c28310e0df | ||
|
|
51435a1c33 | ||
|
|
83c70b9767 | ||
|
|
5534dcd476 | ||
|
|
d18a55deaf | ||
|
|
ae2d64991c | ||
|
|
ecb6b80e5e | ||
|
|
cf332fa67a | ||
|
|
ffa80c9212 | ||
|
|
7463a8f6b5 | ||
|
|
a168897784 | ||
|
|
d39b3856ca | ||
|
|
ca9f74185b | ||
|
|
c35e421ba3 | ||
|
|
65755e0787 | ||
|
|
366c3becc4 | ||
|
|
a1ac6ec543 | ||
|
|
b27bbb7836 | ||
|
|
a57574dd10 | ||
|
|
a7dd22569c | ||
|
|
0bc0755fb3 | ||
|
|
c2edb60218 | ||
|
|
60c1a82a62 | ||
|
|
e3205128b4 | ||
|
|
a9dff0360f | ||
|
|
1e871cbee5 | ||
|
|
41aadf33f3 | ||
|
|
679567c85a | ||
|
|
b77050250c | ||
|
|
e178d1120b | ||
|
|
eca138b671 | ||
|
|
0366aef672 | ||
|
|
30103e5c8f | ||
|
|
cbba7701d8 | ||
|
|
da53bd7db9 | ||
|
|
9e7999da0f | ||
|
|
2c96f991d5 | ||
|
|
67f8127452 | ||
|
|
bce498885e | ||
|
|
eb57a25698 | ||
|
|
4e83e5bf71 | ||
|
|
19a44ce8cf | ||
|
|
0bd0df3245 | ||
|
|
4f0163736f | ||
|
|
8d03f52f09 | ||
|
|
815267a590 | ||
|
|
77f8d442b2 | ||
|
|
aacda5d35e | ||
|
|
58d02f6471 | ||
|
|
c735874cff | ||
|
|
045029b4a9 | ||
|
|
f6b5882cd4 | ||
|
|
63a9005e6b | ||
|
|
c4923f317b | ||
|
|
15e03c0459 | ||
|
|
74f4ddf50b | ||
|
|
fdc868641d | ||
|
|
910eb88c55 | ||
|
|
b597131de4 | ||
|
|
56d5f97556 | ||
|
|
b364dd5811 | ||
|
|
4fec27498c | ||
|
|
7a195ecf23 | ||
|
|
95b7e819cd | ||
|
|
73d243aaf1 | ||
|
|
998fecdd51 | ||
|
|
b1ddc0e3a5 | ||
|
|
641ff4709d | ||
|
|
13f2fbf7d6 | ||
|
|
62f9882314 | ||
|
|
7f270eb9d7 | ||
|
|
974a6bfeaa | ||
|
|
4958b454af | ||
|
|
3531d0963d | ||
|
|
41e6497a2e | ||
|
|
3439fab690 | ||
|
|
14274c8d04 | ||
|
|
b3cbd9be71 | ||
|
|
b1d810188c | ||
|
|
4b48f85162 | ||
|
|
738b02e1b9 | ||
|
|
dc487f9226 | ||
|
|
bb2f43c317 | ||
|
|
be61aef123 | ||
|
|
6ad7888e85 | ||
|
|
242adb3c9e | ||
|
|
8654c69d0c | ||
|
|
a7999ff160 | ||
|
|
9c04b8aab0 | ||
|
|
3643fefc9c | ||
|
|
47189901e5 | ||
|
|
2577684897 | ||
|
|
77396df8fd | ||
|
|
c517a1d469 | ||
|
|
b7d7e6567b | ||
|
|
67807e913e | ||
|
|
19a950dab5 | ||
|
|
79b91f8386 | ||
|
|
0359a4b7e9 | ||
|
|
d89f410749 | ||
|
|
850f6dd060 | ||
|
|
d891c6c8dc | ||
|
|
0a4a88ed5a | ||
|
|
3c02219da0 | ||
|
|
65efc3372e | ||
|
|
3acea66788 | ||
|
|
b448514e40 | ||
|
|
024147344b | ||
|
|
52a34d3871 | ||
|
|
1ada26e4dd | ||
|
|
94d1b61f81 | ||
|
|
29299edb90 | ||
|
|
a2e2c5e178 | ||
|
|
8ae39df2e8 | ||
|
|
508b269a82 | ||
|
|
a8627b6105 | ||
|
|
8fee6b2c68 | ||
|
|
dd58571ffd | ||
|
|
8c25683cc5 | ||
|
|
a96f003b8c | ||
|
|
ff01443246 | ||
|
|
e915a253f8 | ||
|
|
b463389733 | ||
|
|
41c97b92c7 | ||
|
|
1142f81e9c | ||
|
|
5bc9f77b7b | ||
|
|
c5d0582807 | ||
|
|
525e65d152 | ||
|
|
d948c7af47 | ||
|
|
11a29b4ed6 | ||
|
|
e31c4a3041 | ||
|
|
2928d5fc93 | ||
|
|
12fc6f7f10 | ||
|
|
4bd8c207b4 | ||
|
|
be030a3640 | ||
|
|
ebaa250f7b | ||
|
|
826a2d7ee6 | ||
|
|
e476cf8176 | ||
|
|
03115694f9 | ||
|
|
26ffb04834 | ||
|
|
2979fcc33d |
@@ -22,3 +22,8 @@
|
|||||||
由于RedKale使用了JDK 8 内置的ASM包,所以需要在源码工程中的编译器选项中加入: <b>-XDignore.symbol.file=true</b>
|
由于RedKale使用了JDK 8 内置的ASM包,所以需要在源码工程中的编译器选项中加入: <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>欢迎加入Redkale QQ群: 527523235</h5>
|
||||||
|
|
||||||
|
|||||||
36
assembly.xml
Normal file
36
assembly.xml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||||
|
<id>redkale</id>
|
||||||
|
<formats>
|
||||||
|
<format>tar.gz</format>
|
||||||
|
</formats>
|
||||||
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/bin</directory>
|
||||||
|
<outputDirectory>bin</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/conf</directory>
|
||||||
|
<outputDirectory>conf</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/libs</directory>
|
||||||
|
<outputDirectory>libs</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/logs</directory>
|
||||||
|
<outputDirectory>logs</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
<dependencySets>
|
||||||
|
<dependencySet>
|
||||||
|
<useProjectArtifact>true</useProjectArtifact>
|
||||||
|
<useTransitiveDependencies>false</useTransitiveDependencies>
|
||||||
|
<outputDirectory>lib</outputDirectory>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependencySet>
|
||||||
|
</dependencySets>
|
||||||
|
</assembly>
|
||||||
@@ -4,7 +4,7 @@ export LC_ALL="zh_CN.UTF-8"
|
|||||||
|
|
||||||
APP_HOME=`dirname "$0"`
|
APP_HOME=`dirname "$0"`
|
||||||
|
|
||||||
if [ ! -a "$APP_HOME"/conf/application.xml ]; then
|
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
|
||||||
APP_HOME="$APP_HOME"/..
|
APP_HOME="$APP_HOME"/..
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,20 @@ export LC_ALL="zh_CN.UTF-8"
|
|||||||
|
|
||||||
APP_HOME=`dirname "$0"`
|
APP_HOME=`dirname "$0"`
|
||||||
|
|
||||||
if [ ! -a "$APP_HOME"/conf/application.xml ]; then
|
cd "$APP_HOME"/..
|
||||||
|
|
||||||
|
APP_HOME=`pwd`
|
||||||
|
|
||||||
|
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
|
||||||
APP_HOME="$APP_HOME"/..
|
APP_HOME="$APP_HOME"/..
|
||||||
fi
|
fi
|
||||||
|
|
||||||
lib='.'
|
lib="$APP_HOME"/lib
|
||||||
for jar in `ls $APP_HOME/lib/*.jar`
|
for jar in `ls $APP_HOME/lib/*.jar`
|
||||||
do
|
do
|
||||||
lib=$lib:$jar
|
lib=$lib:$jar
|
||||||
done
|
done
|
||||||
export CLASSPATH=$CLASSPATH:$lib
|
export CLASSPATH=$CLASSPATH:$lib
|
||||||
|
|
||||||
echo "$APP_HOME"
|
echo "$APP_HOME"
|
||||||
java -DCMD=SHUTDOWN -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
|
java -DCMD=SHUTDOWN -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ SET APP_HOME=%~dp0
|
|||||||
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
|
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
|
||||||
|
|
||||||
java -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
|
java -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ export LC_ALL="zh_CN.UTF-8"
|
|||||||
|
|
||||||
APP_HOME=`dirname "$0"`
|
APP_HOME=`dirname "$0"`
|
||||||
|
|
||||||
if [ ! -a "$APP_HOME"/conf/application.xml ]; then
|
cd "$APP_HOME"/..
|
||||||
|
|
||||||
|
APP_HOME=`pwd`
|
||||||
|
|
||||||
|
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
|
||||||
APP_HOME="$APP_HOME"/..
|
APP_HOME="$APP_HOME"/..
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<application port="5050">
|
<application port="5050">
|
||||||
|
|
||||||
|
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<!--
|
|
||||||
<properties>
|
|
||||||
<property name="system.property.convert.json.tiny" value="true"/>
|
|
||||||
</properties>
|
|
||||||
-->
|
|
||||||
</resources>
|
|
||||||
|
|
||||||
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
|
</resources>
|
||||||
<!--
|
|
||||||
|
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
|
||||||
|
|
||||||
<request>
|
<request>
|
||||||
<remoteaddr value="request.headers.X-RemoteAddress"/>
|
<remoteaddr value="request.headers.X-RemoteAddress"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<response>
|
<response>
|
||||||
<addheader name="X-Node" value="system.property.APP_NODE" />
|
<defcookie domain="" path=""/>
|
||||||
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
||||||
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
||||||
</response>
|
</response>
|
||||||
-->
|
|
||||||
<services autoload="true"/>
|
<services autoload="true"/>
|
||||||
<servlets path="/pipes" autoload="true" >
|
|
||||||
<!--
|
<filters autoload="true"/>
|
||||||
<resource-servlet>
|
|
||||||
<caches limit="0"/>
|
<rest path="/pipes" /> <!-- base指定的自定义HttpServlet子类必须标记@HttpUserType, 不设置base则视为没有当前用户信息设置 -->
|
||||||
<rewrite type="location" match="^/([^-]+)(-[^-\.]+)+\.html(.*)" forward="/$1.html"/>
|
|
||||||
</resource-servlet>
|
<servlets path="/pipes" autoload="true" />
|
||||||
-->
|
|
||||||
</servlets>
|
|
||||||
</server>
|
</server>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
handlers = java.util.logging.ConsoleHandler
|
handlers = java.util.logging.ConsoleHandler
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
.level = FINE
|
.level = FINER
|
||||||
|
|
||||||
java.level = INFO
|
java.level = INFO
|
||||||
javax.level = INFO
|
javax.level = INFO
|
||||||
@@ -12,12 +12,13 @@ sun.level = INFO
|
|||||||
jdk.level = INFO
|
jdk.level = INFO
|
||||||
|
|
||||||
|
|
||||||
java.util.logging.FileHandler.level = FINE
|
java.util.logging.FileHandler.level = FINER
|
||||||
#10M
|
#10M
|
||||||
java.util.logging.FileHandler.limit = 10485760
|
java.util.logging.FileHandler.limit = 10485760
|
||||||
java.util.logging.FileHandler.count = 10000
|
java.util.logging.FileHandler.count = 10000
|
||||||
java.util.logging.FileHandler.encoding = UTF-8
|
java.util.logging.FileHandler.encoding = UTF-8
|
||||||
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
|
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
|
||||||
|
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
|
||||||
java.util.logging.FileHandler.append = true
|
java.util.logging.FileHandler.append = true
|
||||||
|
|
||||||
java.util.logging.ConsoleHandler.level = FINE
|
java.util.logging.ConsoleHandler.level = FINER
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
<persistence-unit name="user.read" transaction-type="RESOURCE_LOCAL">
|
<persistence-unit name="user.read" transaction-type="RESOURCE_LOCAL">
|
||||||
<shared-cache-mode>ALL</shared-cache-mode>
|
<shared-cache-mode>ALL</shared-cache-mode>
|
||||||
<properties>
|
<properties>
|
||||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/user?autoReconnect=true&characterEncoding=utf8"/>
|
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
|
||||||
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
|
||||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
<property name="javax.persistence.jdbc.user" value="system"/>
|
||||||
<property name="javax.persistence.jdbc.password" value="1234"/>
|
<property name="javax.persistence.jdbc.password" value="1234"/>
|
||||||
</properties>
|
</properties>
|
||||||
</persistence-unit>
|
</persistence-unit>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>
|
<EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>
|
||||||
1
libs/readme.txt
Normal file
1
libs/readme.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>
|
||||||
40
pom.xml
40
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<url>http://redkale.org</url>
|
<url>http://redkale.org</url>
|
||||||
<description>redkale -- java framework</description>
|
<description>redkale -- java framework</description>
|
||||||
<version>1.4.0-SNAPSHOT</version>
|
<version>1.6.2</version>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>Apache 2</name>
|
<name>Apache 2</name>
|
||||||
@@ -121,20 +121,30 @@
|
|||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
<configuration>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>assembly.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>redkale</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.plexus</groupId>
|
|
||||||
<artifactId>plexus-compiler-javac</artifactId>
|
|
||||||
<version>2.7</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.plexus</groupId>
|
|
||||||
<artifactId>plexus-utils</artifactId>
|
|
||||||
<version>3.0.22</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
</project>
|
||||||
@@ -23,27 +23,30 @@
|
|||||||
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 port="6560" lib="">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
【节点全局唯一】
|
【节点全局唯一】
|
||||||
所有服务所需的资源
|
所有服务所需的资源
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
【节点全局唯一】
|
【节点全局唯一】
|
||||||
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
||||||
threads: 线程总数, 默认: <group>节点数*CPU核数*8
|
threads: 线程总数, 默认: <group>节点数*CPU核数*8
|
||||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 8K;
|
bufferCapacity: ByteBuffer的初始化大小, 默认: 8K;
|
||||||
bufferPoolSize: ByteBuffer池的大小,默认: <group>节点数*CPU核数*8
|
bufferPoolSize: ByteBuffer池的大小,默认: <group>节点数*CPU核数*8
|
||||||
|
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
|
||||||
-->
|
-->
|
||||||
<transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/>
|
<transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
一个组包含多个NODE, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
一个组包含多个node, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
||||||
一个group节点对应一个 Transport 对象。
|
一个group节点对应一个 Transport 对象。
|
||||||
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
||||||
protocol:值只能是UDP TCP, 默认TCP
|
protocol:值范围:UDP TCP, 默认TCP
|
||||||
kind: 与SNCP服务连接时的数据传输类型;可选值有:rest(不区分大小写);值为空或空字符串表示按SNCP协议传输; 为rest表示按REST传输。默认值为空
|
subprotocol: 子协议,预留字段。默认值为空
|
||||||
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
||||||
-->
|
-->
|
||||||
<group name="" protocol="TCP">
|
<group name="" protocol="TCP">
|
||||||
@@ -57,9 +60,27 @@
|
|||||||
-->
|
-->
|
||||||
<node addr="127.0.0.1" port="7070"/>
|
<node addr="127.0.0.1" port="7070"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
全局的数据源设置, 可以是CacheSource、DataSource, JDBC的DataSource通常通过persistence.xml配置,此处多用于CacheSource的配置
|
||||||
|
name: 资源名,用于依赖注入。
|
||||||
|
value:类名,必须是CacheSource或DataSource的子类,且必须实现Service接口。
|
||||||
|
groups: 指定groups。
|
||||||
|
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
|
||||||
|
-->
|
||||||
|
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
|
||||||
|
<node addr="127.0.0.1" port="7070"/>
|
||||||
|
</source>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Application启动的监听事件,可配置多个节点
|
||||||
|
value: 类名,必须是ApplicationListener的子类
|
||||||
|
-->
|
||||||
|
<listener value="org.redkalex.xxx.XXXApplicationListener"/>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
【节点全局唯一】
|
【节点全局唯一】
|
||||||
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入, 被注解的字段类型只能是String、primitive class
|
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
|
||||||
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
||||||
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
||||||
load: 加载文件,多个用;隔开。
|
load: 加载文件,多个用;隔开。
|
||||||
@@ -70,6 +91,8 @@
|
|||||||
System.setProperty("convert.bson.pool.size", "128");
|
System.setProperty("convert.bson.pool.size", "128");
|
||||||
System.setProperty("convert.json.writer.buffer.defsize", "4096");
|
System.setProperty("convert.json.writer.buffer.defsize", "4096");
|
||||||
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
|
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
|
||||||
|
|
||||||
|
<properties>节点下也可包含非<property>节点,其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
|
||||||
-->
|
-->
|
||||||
<properties load="config.properties">
|
<properties load="config.properties">
|
||||||
<property name="system.property.yyyy" value="YYYYYY"/>
|
<property name="system.property.yyyy" value="YYYYYY"/>
|
||||||
@@ -77,20 +100,22 @@
|
|||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
<!--
|
<!--
|
||||||
protocol: required server所启动的协议,Redkale内置的有HTTP、SNCP,SNCP使用TCP实现;
|
protocol: required server所启动的协议,Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
|
||||||
name: 服务的名称,用于监控识别,一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线、减号
|
name: 服务的名称,用于监控识别,一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
|
||||||
host: 服务所占address , 默认: 0.0.0.0
|
host: 服务所占address , 默认: 0.0.0.0
|
||||||
port: required 服务所占端口
|
port: required 服务所占端口
|
||||||
root: 如果是web类型服务,则包含页面 默认:{APP_HOME}/root
|
root: 如果是web类型服务,则包含页面 默认:{APP_HOME}/root
|
||||||
lib: server额外的class目录, 默认为空
|
lib: server额外的class目录, 默认为${APP_HOME}/libs/*;
|
||||||
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||||
charset: 文本编码, 默认: UTF-8
|
charset: 文本编码, 默认: UTF-8
|
||||||
backlog: 默认10K
|
backlog: 默认10K
|
||||||
threads: 线程总数, 默认: CPU核数*16
|
threads: 线程总数, 默认: CPU核数*16
|
||||||
|
maxconns:最大连接数, 小于1表示无限制, 默认: 0
|
||||||
maxbody: request.body最大值, 默认: 64K
|
maxbody: request.body最大值, 默认: 64K
|
||||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 8K; 如果是HTTP协议则默认: 16K + 8B (兼容HTTP 2.0)
|
bufferCapacity: ByteBuffer的初始化大小, 默认: 8K; 如果是HTTP协议则默认: 16K + 16B (兼容HTTP 2.0、WebSocket)
|
||||||
bufferPoolSize: ByteBuffer池的大小,默认: CPU核数*512
|
bufferPoolSize: ByteBuffer池的大小,默认: CPU核数*512
|
||||||
responsePoolSize: Response池的大小,默认: CPU核数*256
|
responsePoolSize: Response池的大小,默认: CPU核数*256
|
||||||
readTimeoutSecond: 读操作超时秒数, 默认0, 表示永久不超时
|
readTimeoutSecond: 读操作超时秒数, 默认0, 表示永久不超时
|
||||||
@@ -102,8 +127,7 @@
|
|||||||
<!--
|
<!--
|
||||||
加载所有的Service服务;
|
加载所有的Service服务;
|
||||||
在同一个进程中同一个name同一类型的Service将共用同一个实例
|
在同一个进程中同一个name同一类型的Service将共用同一个实例
|
||||||
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Service类:
|
autoload="true" 默认值. 自动加载classpath下所有的Service类
|
||||||
server.lib; server.lib/*; server.classes;
|
|
||||||
autoload="false" 需要显著的指定Service类
|
autoload="false" 需要显著的指定Service类
|
||||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
@@ -118,6 +142,7 @@
|
|||||||
<!--
|
<!--
|
||||||
name: 显式指定name,覆盖默认的空字符串值。 注意: name不能包含$符号。
|
name: 显式指定name,覆盖默认的空字符串值。 注意: name不能包含$符号。
|
||||||
groups: 显式指定groups,覆盖<services>节点的groups默认值。
|
groups: 显式指定groups,覆盖<services>节点的groups默认值。
|
||||||
|
ignore: 是否禁用, 默认为false。
|
||||||
-->
|
-->
|
||||||
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
|
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
|
||||||
<!-- 给Service增加配置属性 -->
|
<!-- 给Service增加配置属性 -->
|
||||||
@@ -128,21 +153,51 @@
|
|||||||
</service>
|
</service>
|
||||||
</services>
|
</services>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
加载所有的Filter服务;
|
||||||
|
autoload="true" 默认值.
|
||||||
|
autoload="false" 需要显著的指定Filter类
|
||||||
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
-->
|
||||||
|
<filters autoload="true" includes="" excludes="">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
显著加载指定的Filter类
|
||||||
|
value=: Filter类名。必须与Server的协议层相同,HTTP必须是HttpFilter
|
||||||
|
ignore: 是否禁用, 默认为false。
|
||||||
|
-->
|
||||||
|
<!-- 显著加载指定的Filter类 -->
|
||||||
|
<filter value="com.xxx.XXX1Filter"/>
|
||||||
|
|
||||||
|
<!-- 给Filter增加配置属性 -->
|
||||||
|
<filter value="com.xxx.XXX12Filter">
|
||||||
|
<!-- property节点值在 public void init(AnyValue conf) 方法中可以通过 AnyValue properties = conf.getAnyValue("properties");获取 -->
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
REST的核心配置项
|
REST的核心配置项
|
||||||
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个
|
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置,系统会自动生成)
|
||||||
base: REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
|
path: servlet的ContextPath前缀 默认为空
|
||||||
|
base: REST服务的BaseServlet,必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
|
||||||
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
|
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
|
||||||
mustsign:默认值"true" 是否只加载标记为RestService的Service类,默认只加载标记RestService且ignore=false的Service
|
|
||||||
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
-->
|
-->
|
||||||
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes="">
|
<rest path="/pipes" base="org.redkale.net.http.HttpServlet" autoload="true" includes="" excludes="">
|
||||||
<!--
|
<!--
|
||||||
value: Service类名,列出的表示必须被加载的Service对象
|
value: Service类名,列出的表示必须被加载的Service对象
|
||||||
ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
|
ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
|
||||||
-->
|
-->
|
||||||
<service value="com.xxx.XXXXService"/>
|
<service value="com.xxx.XXXXService"/>
|
||||||
|
<!--
|
||||||
|
value: WebSocket类名,列出的表示必须被加载且标记为@RestWebSocket的WebSocket对象
|
||||||
|
ignore: 是否忽略,设置为true则不会加载该RestWebSocket对象,默认值为false
|
||||||
|
-->
|
||||||
|
<websocket value="com.xxx.XXXXRestWebSocket"/>
|
||||||
</rest>
|
</rest>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -163,11 +218,14 @@
|
|||||||
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
|
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
|
||||||
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
|
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
|
||||||
例如下面例子是在Response输出header时添加两个header(一个addHeader, 一个setHeader)。
|
例如下面例子是在Response输出header时添加两个header(一个addHeader, 一个setHeader)。
|
||||||
|
options 节点: 设置了该节点却auto=true,当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
|
||||||
-->
|
-->
|
||||||
<response>
|
<response>
|
||||||
<defcookie domain="" path=""/>
|
<defcookie domain="" path=""/>
|
||||||
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
||||||
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/>
|
||||||
|
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
||||||
|
<options auto="true" />
|
||||||
</response>
|
</response>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -198,14 +256,17 @@
|
|||||||
<!--
|
<!--
|
||||||
加载所有的Servlet服务;
|
加载所有的Servlet服务;
|
||||||
path: servlet的ContextPath前缀 默认为空
|
path: servlet的ContextPath前缀 默认为空
|
||||||
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Servlet类:
|
autoload="true" 默认值. 自动加载classpath下所有的Servlet类
|
||||||
${APP_HOME}/lib; ${APP_HOME}/root/lib/*; ${APP_HOME}/root/classes;
|
|
||||||
autoload="false" 需要显著的指定Service类
|
autoload="false" 需要显著的指定Service类
|
||||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
-->
|
-->
|
||||||
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
||||||
<!-- 显著加载指定的Servlet -->
|
<!--
|
||||||
|
显著加载指定的Servlet类
|
||||||
|
value=: Servlet类名。必须与Server的协议层相同,HTTP必须是HttpServlet
|
||||||
|
ignore: 是否禁用, 默认为false。
|
||||||
|
-->
|
||||||
<servlet value="com.xxx.XXX1Servlet" />
|
<servlet value="com.xxx.XXX1Servlet" />
|
||||||
<servlet value="com.xxx.XXX2Servlet" />
|
<servlet value="com.xxx.XXX2Servlet" />
|
||||||
<servlet value="com.xxx.XXX3Servlet" >
|
<servlet value="com.xxx.XXX3Servlet" >
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ com.sun.level = INFO
|
|||||||
java.util.logging.FileHandler.limit = 10485760
|
java.util.logging.FileHandler.limit = 10485760
|
||||||
java.util.logging.FileHandler.count = 100
|
java.util.logging.FileHandler.count = 100
|
||||||
java.util.logging.FileHandler.encoding = UTF-8
|
java.util.logging.FileHandler.encoding = UTF-8
|
||||||
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%u.log
|
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
|
||||||
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
|
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
|
||||||
#java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-error-%u.log
|
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
|
||||||
java.util.logging.FileHandler.append = true
|
java.util.logging.FileHandler.append = true
|
||||||
|
|
||||||
#java.util.logging.ConsoleHandler.level = FINE
|
#java.util.logging.ConsoleHandler.level = FINE
|
||||||
|
|||||||
@@ -3,9 +3,16 @@
|
|||||||
<persistence>
|
<persistence>
|
||||||
<!-- 系统基本库 -->
|
<!-- 系统基本库 -->
|
||||||
<persistence-unit name="demouser">
|
<persistence-unit name="demouser">
|
||||||
<!-- 为NONE表示不启动缓存,@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
|
|
||||||
<shared-cache-mode>NONE</shared-cache-mode>
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<!--
|
||||||
|
DataSource的实现类,没有设置默认为org.redkale.source.DataJdbcSource的实现,使用常规基于JDBC的数据库驱动一般无需设置
|
||||||
|
-->
|
||||||
|
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
|
||||||
|
<!--
|
||||||
|
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存
|
||||||
|
-->
|
||||||
|
<property name="javax.persistence.cachemode" value="ALL"/>
|
||||||
|
|
||||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
|
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
|
||||||
<!--
|
<!--
|
||||||
javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。
|
javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。
|
||||||
@@ -37,7 +44,6 @@
|
|||||||
</persistence-unit>
|
</persistence-unit>
|
||||||
<!-- IM消息库 -->
|
<!-- IM消息库 -->
|
||||||
<persistence-unit name="demoim">
|
<persistence-unit name="demoim">
|
||||||
<shared-cache-mode>NONE</shared-cache-mode>
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&autoReconnectForPools=true&characterEncoding=utf8 -->
|
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&autoReconnectForPools=true&characterEncoding=utf8 -->
|
||||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
|
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
|
||||||
|
|||||||
33
src/javax/annotation/Priority.java
Normal file
33
src/javax/annotation/Priority.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package javax.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值越大,优先级越高
|
||||||
|
*
|
||||||
|
* @since Common Annotations 1.2
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Priority {
|
||||||
|
int value();
|
||||||
|
}
|
||||||
32
src/javax/annotation/Resource.java
Normal file
32
src/javax/annotation/Resource.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 javax.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since Common Annotations 1.0
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Resource {
|
||||||
|
public enum AuthenticationType {
|
||||||
|
CONTAINER,
|
||||||
|
APPLICATION
|
||||||
|
}
|
||||||
|
public String name() default "";
|
||||||
|
|
||||||
|
public Class<?> type() default Object.class;
|
||||||
|
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
|
||||||
|
public boolean shareable() default true;
|
||||||
|
public String description() default "";
|
||||||
|
public String mappedName() default "";
|
||||||
|
|
||||||
|
public String lookup() default "";
|
||||||
|
}
|
||||||
29
src/module-info.java
Normal file
29
src/module-info.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* see: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
module org.redkale {
|
||||||
|
|
||||||
|
requires java.se;
|
||||||
|
requires jdk.unsupported;
|
||||||
|
|
||||||
|
exports javax.annotation;
|
||||||
|
exports javax.persistence;
|
||||||
|
exports org.redkale.boot;
|
||||||
|
exports org.redkale.boot.watch;
|
||||||
|
exports org.redkale.convert;
|
||||||
|
exports org.redkale.convert.bson;
|
||||||
|
exports org.redkale.convert.ext;
|
||||||
|
exports org.redkale.convert.json;
|
||||||
|
exports org.redkale.net;
|
||||||
|
exports org.redkale.net.http;
|
||||||
|
exports org.redkale.net.sncp;
|
||||||
|
exports org.redkale.service;
|
||||||
|
exports org.redkale.source;
|
||||||
|
exports org.redkale.util;
|
||||||
|
exports org.redkale.watch;
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
42
src/org/redkale/asm/asm.txt
Normal file
42
src/org/redkale/asm/asm.txt
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
need copy classes:
|
||||||
|
|
||||||
|
AnnotationVisitor.java
|
||||||
|
AnnotationWriter.java
|
||||||
|
Attribute.java
|
||||||
|
ByteVector.java
|
||||||
|
ClassReader.java
|
||||||
|
ClassVisitor.java
|
||||||
|
ClassWriter.java
|
||||||
|
Context.java
|
||||||
|
Edge.java
|
||||||
|
FieldVisitor.java
|
||||||
|
FieldWriter.java
|
||||||
|
Frame.java
|
||||||
|
Handle.java
|
||||||
|
Handler.java
|
||||||
|
Item.java
|
||||||
|
Label.java
|
||||||
|
MethodVisitor.java
|
||||||
|
MethodWriter.java
|
||||||
|
Opcodes.java
|
||||||
|
Type.java
|
||||||
|
TypePath.java
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
File srcasmroot = new File("D:/JAVA/JDK源码/JDK9源码/java.base/jdk/internal/org/objectweb/asm");
|
||||||
|
File destasmroot = new File("D:/Java-Projects/RedkaleProject/src/org/redkale/asm");
|
||||||
|
String line = null;
|
||||||
|
LineNumberReader txtin = new LineNumberReader(new FileReader(new File(destasmroot, "asm.txt")));
|
||||||
|
while ((line = txtin.readLine()) != null) {
|
||||||
|
line = line.trim();
|
||||||
|
if (!line.endsWith(".java")) continue;
|
||||||
|
File srcfile = new File(srcasmroot, line);
|
||||||
|
File destfile = new File(destasmroot, line);
|
||||||
|
String content = Utility.readThenClose(new FileInputStream(srcfile));
|
||||||
|
FileOutputStream out = new FileOutputStream(destfile);
|
||||||
|
out.write(content.replace("jdk.internal.org.objectweb", "org.redkale").getBytes());
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,23 +15,26 @@ import org.redkale.source.*;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 继承 HttpBaseServlet 是为了获取 WebAction 信息
|
* API接口文档生成类,作用:生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
|
||||||
|
* 继承 HttpBaseServlet 是为了获取 WebMapping 信息
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class ApiDocs extends HttpBaseServlet {
|
public final class ApiDocsService {
|
||||||
|
|
||||||
private final Application app;
|
private final Application app; //Application全局对象
|
||||||
|
|
||||||
public ApiDocs(Application app) {
|
public ApiDocsService(Application app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
List<Map> serverList = new ArrayList<>();
|
List<Map> serverList = new ArrayList<>();
|
||||||
|
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
|
||||||
|
__prefix.setAccessible(true);
|
||||||
Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
|
Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
|
||||||
for (NodeServer node : app.servers) {
|
for (NodeServer node : app.servers) {
|
||||||
if (!(node instanceof NodeHttpServer)) continue;
|
if (!(node instanceof NodeHttpServer)) continue;
|
||||||
@@ -49,20 +52,20 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final Map<String, Object> servletmap = new LinkedHashMap<>();
|
final Map<String, Object> servletmap = new LinkedHashMap<>();
|
||||||
String prefix = _prefix(servlet);
|
String prefix = (String) __prefix.get(servlet);
|
||||||
String[] mappings = ws.value();
|
String[] urlregs = ws.value();
|
||||||
if (prefix != null && !prefix.isEmpty()) {
|
if (prefix != null && !prefix.isEmpty()) {
|
||||||
for (int i = 0; i < mappings.length; i++) {
|
for (int i = 0; i < urlregs.length; i++) {
|
||||||
mappings[i] = prefix + mappings[i];
|
urlregs[i] = prefix + urlregs[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
servletmap.put("mappings", mappings);
|
servletmap.put("urlregs", urlregs);
|
||||||
servletmap.put("moduleid", ws.moduleid());
|
servletmap.put("moduleid", ws.moduleid());
|
||||||
servletmap.put("name", ws.name());
|
servletmap.put("name", ws.name());
|
||||||
servletmap.put("comment", ws.comment());
|
servletmap.put("comment", ws.comment());
|
||||||
|
|
||||||
List<Map> actionsList = new ArrayList<>();
|
List<Map> mappingsList = new ArrayList<>();
|
||||||
servletmap.put("actions", actionsList);
|
servletmap.put("mappings", mappingsList);
|
||||||
final Class selfClz = servlet.getClass();
|
final Class selfClz = servlet.getClass();
|
||||||
Class clz = servlet.getClass();
|
Class clz = servlet.getClass();
|
||||||
HashSet<String> actionurls = new HashSet<>();
|
HashSet<String> actionurls = new HashSet<>();
|
||||||
@@ -70,18 +73,18 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
if (Modifier.isAbstract(clz.getModifiers())) break;
|
if (Modifier.isAbstract(clz.getModifiers())) break;
|
||||||
for (Method method : clz.getMethods()) {
|
for (Method method : clz.getMethods()) {
|
||||||
if (method.getParameterCount() != 2) continue;
|
if (method.getParameterCount() != 2) continue;
|
||||||
WebAction action = method.getAnnotation(WebAction.class);
|
HttpMapping action = method.getAnnotation(HttpMapping.class);
|
||||||
if (action == null) continue;
|
if (action == null) continue;
|
||||||
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
|
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
|
||||||
final Map<String, Object> actionmap = new LinkedHashMap<>();
|
final Map<String, Object> mappingmap = new LinkedHashMap<>();
|
||||||
if (actionurls.contains(action.url())) continue;
|
if (actionurls.contains(action.url())) continue;
|
||||||
actionmap.put("url", prefix + action.url());
|
mappingmap.put("url", prefix + action.url());
|
||||||
actionurls.add(action.url());
|
actionurls.add(action.url());
|
||||||
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
|
mappingmap.put("auth", action.auth());
|
||||||
actionmap.put("actionid", action.actionid());
|
mappingmap.put("actionid", action.actionid());
|
||||||
actionmap.put("comment", action.comment());
|
mappingmap.put("comment", action.comment());
|
||||||
List<Map> paramsList = new ArrayList<>();
|
List<Map> paramsList = new ArrayList<>();
|
||||||
actionmap.put("params", paramsList);
|
mappingmap.put("params", paramsList);
|
||||||
List<String> results = new ArrayList<>();
|
List<String> results = new ArrayList<>();
|
||||||
for (final Class rtype : action.results()) {
|
for (final Class rtype : action.results()) {
|
||||||
results.add(rtype.getName());
|
results.add(rtype.getName());
|
||||||
@@ -110,7 +113,7 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
}
|
}
|
||||||
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
|
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
|
||||||
fieldmap.put("updatable", (filter || col == null || col.updatable()));
|
fieldmap.put("updatable", (filter || col == null || col.updatable()));
|
||||||
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
|
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
|
||||||
if (field.getAnnotation(RestAddress.class) != null) continue;
|
if (field.getAnnotation(RestAddress.class) != null) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,8 +122,8 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
} while ((loop = loop.getSuperclass()) != Object.class);
|
} while ((loop = loop.getSuperclass()) != Object.class);
|
||||||
typesmap.put(rtype.getName(), typemap);
|
typesmap.put(rtype.getName(), typemap);
|
||||||
}
|
}
|
||||||
actionmap.put("results", results);
|
mappingmap.put("results", results);
|
||||||
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
|
for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
|
||||||
final Map<String, Object> parammap = new LinkedHashMap<>();
|
final Map<String, Object> parammap = new LinkedHashMap<>();
|
||||||
final boolean isarray = param.type().isArray();
|
final boolean isarray = param.type().isArray();
|
||||||
final Class ptype = isarray ? param.type().getComponentType() : param.type();
|
final Class ptype = isarray ? param.type().getComponentType() : param.type();
|
||||||
@@ -159,7 +162,7 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
|
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
|
||||||
fieldmap.put("updatable", (filter || col == null || col.updatable()));
|
fieldmap.put("updatable", (filter || col == null || col.updatable()));
|
||||||
|
|
||||||
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
|
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
|
||||||
if (field.getAnnotation(RestAddress.class) != null) continue;
|
if (field.getAnnotation(RestAddress.class) != null) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,17 +172,17 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
|
|
||||||
typesmap.put(ptype.getName(), typemap);
|
typesmap.put(ptype.getName(), typemap);
|
||||||
}
|
}
|
||||||
actionmap.put("result", action.result());
|
mappingmap.put("result", action.result());
|
||||||
actionsList.add(actionmap);
|
mappingsList.add(mappingmap);
|
||||||
}
|
}
|
||||||
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
|
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
|
||||||
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
|
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
|
||||||
servletsList.add(servletmap);
|
servletsList.add(servletmap);
|
||||||
}
|
}
|
||||||
servletsList.sort((o1, o2) -> {
|
servletsList.sort((o1, o2) -> {
|
||||||
String[] mappings1 = (String[]) o1.get("mappings");
|
String[] urlregs1 = (String[]) o1.get("urlregs");
|
||||||
String[] mappings2 = (String[]) o2.get("mappings");
|
String[] urlregs2 = (String[]) o2.get("urlregs");
|
||||||
return mappings1.length > 0 ? (mappings2.length > 0 ? mappings1[0].compareTo(mappings2[0]) : 1) : -1;
|
return urlregs1.length > 0 ? (urlregs2.length > 0 ? urlregs1[0].compareTo(urlregs2[0]) : 1) : -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Map<String, Object> resultmap = new LinkedHashMap<>();
|
Map<String, Object> resultmap = new LinkedHashMap<>();
|
||||||
@@ -194,7 +197,7 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
if (doctemplate.isFile() && doctemplate.canRead()) {
|
if (doctemplate.isFile() && doctemplate.canRead()) {
|
||||||
in = new FileInputStream(doctemplate);
|
in = new FileInputStream(doctemplate);
|
||||||
}
|
}
|
||||||
if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html");
|
if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html");
|
||||||
String content = Utility.read(in).replace("'${content}'", json);
|
String content = Utility.read(in).replace("'${content}'", json);
|
||||||
in.close();
|
in.close();
|
||||||
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
|
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
|
||||||
@@ -202,8 +205,4 @@ public class ApiDocs extends HttpBaseServlet {
|
|||||||
outhtml.close();
|
outhtml.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,8 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
|
import org.redkale.net.TransportGroupInfo;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
@@ -15,24 +17,34 @@ import java.util.*;
|
|||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
import javax.annotation.Resource;
|
||||||
import javax.xml.parsers.*;
|
import javax.xml.parsers.*;
|
||||||
import org.redkale.boot.ClassFilter.FilterEntry;
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.convert.Convert;
|
||||||
import org.redkale.convert.bson.BsonFactory;
|
import org.redkale.convert.bson.BsonFactory;
|
||||||
import org.redkale.convert.json.JsonFactory;
|
import org.redkale.convert.json.JsonFactory;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.http.MimeType;
|
import org.redkale.net.http.MimeType;
|
||||||
import org.redkale.net.sncp.SncpClient;
|
import org.redkale.net.sncp.*;
|
||||||
import org.redkale.service.Service;
|
import org.redkale.service.Service;
|
||||||
import org.redkale.source.*;
|
import org.redkale.source.*;
|
||||||
import org.redkale.util.AnyValue.DefaultAnyValue;
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
import org.redkale.watch.WatchFactory;
|
import org.redkale.watch.*;
|
||||||
import org.w3c.dom.*;
|
import org.w3c.dom.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编译时需要加入: -XDignore.symbol.file=true
|
*
|
||||||
|
* 进程启动类,全局对象。 <br>
|
||||||
|
* <pre>
|
||||||
|
* 程序启动执行步骤:
|
||||||
|
* 1、读取application.xml
|
||||||
|
* 2、进行classpath扫描动态加载Service、WebSocket与Servlet
|
||||||
|
* 3、优先加载所有SNCP协议的服务,再加载其他协议服务, 最后加载WATCH协议的服务
|
||||||
|
* 4、最后进行Service、Servlet与其他资源之间的依赖注入
|
||||||
|
* </pre>
|
||||||
* <p>
|
* <p>
|
||||||
* 进程启动类,程序启动后读取application.xml,进行classpath扫描动态加载Service与Servlet 优先加载所有SNCP协议的服务, 再加载其他协议服务, 最后进行Service、Servlet与其他资源之间的依赖注入。
|
* 编译时需要加入: -XDignore.symbol.file=true
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
@@ -40,67 +52,100 @@ import org.w3c.dom.*;
|
|||||||
*/
|
*/
|
||||||
public final class Application {
|
public final class Application {
|
||||||
|
|
||||||
//当前进程启动的时间, 类型: long
|
/**
|
||||||
|
* 当前进程启动的时间, 类型: long
|
||||||
|
*/
|
||||||
public static final String RESNAME_APP_TIME = "APP_TIME";
|
public static final String RESNAME_APP_TIME = "APP_TIME";
|
||||||
|
|
||||||
//当前进程的根目录, 类型:String、File、Path
|
/**
|
||||||
|
* 当前进程的根目录, 类型:String、File、Path
|
||||||
|
*/
|
||||||
public static final String RESNAME_APP_HOME = "APP_HOME";
|
public static final String RESNAME_APP_HOME = "APP_HOME";
|
||||||
|
|
||||||
//application.xml 文件中resources节点的内容, 类型: AnyValue
|
/**
|
||||||
|
* application.xml 文件中resources节点的内容, 类型: AnyValue
|
||||||
|
*/
|
||||||
public static final String RESNAME_APP_GRES = "APP_GRES";
|
public static final String RESNAME_APP_GRES = "APP_GRES";
|
||||||
|
|
||||||
//当前进程节点的name, 类型:String
|
/**
|
||||||
|
* 当前进程节点的name, 类型:String
|
||||||
|
*/
|
||||||
public static final String RESNAME_APP_NODE = "APP_NODE";
|
public static final String RESNAME_APP_NODE = "APP_NODE";
|
||||||
|
|
||||||
//当前进程节点的IP地址, 类型:InetAddress、String
|
/**
|
||||||
|
* 当前进程节点的IP地址, 类型:InetAddress、String
|
||||||
|
*/
|
||||||
public static final String RESNAME_APP_ADDR = "APP_ADDR";
|
public static final String RESNAME_APP_ADDR = "APP_ADDR";
|
||||||
|
|
||||||
//当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
|
/**
|
||||||
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR";
|
* 当前Service所属的SNCP Server的地址 类型: SocketAddress、InetSocketAddress、String <br>
|
||||||
|
*/
|
||||||
|
public static final String RESNAME_SNCP_ADDR = "SNCP_ADDR";
|
||||||
|
|
||||||
//当前SNCP Server所属的组 类型: String
|
/**
|
||||||
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP";
|
* 当前Service所属的SNCP Server所属的组 类型: String<br>
|
||||||
|
*/
|
||||||
|
public static final String RESNAME_SNCP_GROUP = "SNCP_GROUP";
|
||||||
|
|
||||||
//当前Server的ROOT目录 类型:String、File、Path
|
/**
|
||||||
|
* "SERVER_ROOT" 当前Server的ROOT目录类型:String、File、Path
|
||||||
|
*/
|
||||||
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
|
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
|
||||||
|
|
||||||
final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
|
//本地IP地址
|
||||||
|
|
||||||
final Map<String, GroupInfo> globalGroups = new HashMap<>();
|
|
||||||
|
|
||||||
final InetAddress localAddress;
|
final InetAddress localAddress;
|
||||||
|
|
||||||
|
//CacheSource 资源
|
||||||
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
|
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
//DataSource 资源
|
||||||
final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
|
final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
//NodeServer 资源
|
||||||
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
|
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
final ObjectPool<ByteBuffer> transportBufferPool;
|
//SNCP传输端的TransportFactory, 注意: 只给SNCP使用
|
||||||
|
final TransportFactory sncpTransportFactory;
|
||||||
final ExecutorService transportExecutor;
|
|
||||||
|
|
||||||
final AsynchronousChannelGroup transportChannelGroup;
|
|
||||||
|
|
||||||
|
//全局根ResourceFactory
|
||||||
final ResourceFactory resourceFactory = ResourceFactory.root();
|
final ResourceFactory resourceFactory = ResourceFactory.root();
|
||||||
|
|
||||||
|
//服务配置项
|
||||||
|
final AnyValue config;
|
||||||
|
|
||||||
|
//临时计数器
|
||||||
CountDownLatch servicecdl; //会出现两次赋值
|
CountDownLatch servicecdl; //会出现两次赋值
|
||||||
|
|
||||||
|
//是否启动了WATCH协议服务
|
||||||
|
boolean watching;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------
|
||||||
|
//是否用于main方法运行
|
||||||
private final boolean singletonrun;
|
private final boolean singletonrun;
|
||||||
|
|
||||||
private final WatchFactory watchFactory = WatchFactory.root();
|
//根WatchFactory
|
||||||
|
//private final WatchFactory watchFactory = WatchFactory.root();
|
||||||
|
//进程根目录
|
||||||
private final File home;
|
private final File home;
|
||||||
|
|
||||||
|
//日志
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
|
||||||
private final AnyValue config;
|
//监听事件
|
||||||
|
private final List<ApplicationListener> listeners = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
//服务启动时间
|
||||||
private final long startTime = System.currentTimeMillis();
|
private final long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
//Server启动的计数器,用于确保所有Server都启动完后再进行下一步处理
|
||||||
private final CountDownLatch serversLatch;
|
private final CountDownLatch serversLatch;
|
||||||
|
|
||||||
|
//根ClassLoader
|
||||||
|
private final RedkaleClassLoader classLoader;
|
||||||
|
|
||||||
|
//Server根ClassLoader
|
||||||
|
private final RedkaleClassLoader serverClassLoader;
|
||||||
|
|
||||||
private Application(final AnyValue config) {
|
private Application(final AnyValue config) {
|
||||||
this(false, config);
|
this(false, config);
|
||||||
}
|
}
|
||||||
@@ -164,7 +209,8 @@ public final class Application {
|
|||||||
Properties prop = new Properties();
|
Properties prop = new Properties();
|
||||||
final String handlers = properties.getProperty("handlers");
|
final String handlers = properties.getProperty("handlers");
|
||||||
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
|
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
|
||||||
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", fileHandlerClass));
|
//singletonrun模式下不输出文件日志
|
||||||
|
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", singletonrun ? "" : fileHandlerClass));
|
||||||
}
|
}
|
||||||
if (!prop.isEmpty()) {
|
if (!prop.isEmpty()) {
|
||||||
String prefix = fileHandlerClass + ".";
|
String prefix = fileHandlerClass + ".";
|
||||||
@@ -189,31 +235,40 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
this.logger = Logger.getLogger(this.getClass().getSimpleName());
|
this.logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
|
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
|
||||||
logger.log(Level.INFO, "------------------------------- Redkale ------------------------------");
|
this.classLoader = new RedkaleClassLoader(Thread.currentThread().getContextClassLoader());
|
||||||
|
logger.log(Level.INFO, "------------------------- Redkale " + Redkale.getDotedVersion() + " -------------------------");
|
||||||
//------------------配置 <transport> 节点 ------------------
|
//------------------配置 <transport> 节点 ------------------
|
||||||
ObjectPool<ByteBuffer> transportPool = null;
|
ObjectPool<ByteBuffer> transportPool = null;
|
||||||
ExecutorService transportExec = null;
|
ExecutorService transportExec = null;
|
||||||
AsynchronousChannelGroup transportGroup = null;
|
AsynchronousChannelGroup transportGroup = null;
|
||||||
final AnyValue resources = config.getAnyValue("resources");
|
final AnyValue resources = config.getAnyValue("resources");
|
||||||
|
TransportStrategy strategy = null;
|
||||||
|
int bufferCapacity = 8 * 1024;
|
||||||
|
int bufferPoolSize = Runtime.getRuntime().availableProcessors() * 16;
|
||||||
|
AtomicLong createBufferCounter = new AtomicLong();
|
||||||
|
AtomicLong cycleBufferCounter = new AtomicLong();
|
||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
AnyValue transportConf = resources.getAnyValue("transport");
|
AnyValue transportConf = resources.getAnyValue("transport");
|
||||||
int groupsize = resources.getAnyValues("group").length;
|
int groupsize = resources.getAnyValues("group").length;
|
||||||
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
|
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
|
||||||
if (transportConf != null) {
|
if (transportConf != null) {
|
||||||
//--------------transportBufferPool-----------
|
//--------------transportBufferPool-----------
|
||||||
AtomicLong createBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.creatCounter");
|
bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), bufferCapacity), 4 * 1024);
|
||||||
AtomicLong cycleBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.cycleCounter");
|
bufferPoolSize = parseLenth(transportConf.getValue("bufferPoolSize"), groupsize * Runtime.getRuntime().availableProcessors() * 8);
|
||||||
final int bufferCapacity = transportConf.getIntValue("bufferCapacity", 8 * 1024);
|
final int threads = parseLenth(transportConf.getValue("threads"), groupsize * Runtime.getRuntime().availableProcessors() * 8);
|
||||||
final int bufferPoolSize = transportConf.getIntValue("bufferPoolSize", groupsize * Runtime.getRuntime().availableProcessors() * 8);
|
final int capacity = bufferCapacity;
|
||||||
final int threads = transportConf.getIntValue("threads", groupsize * Runtime.getRuntime().availableProcessors() * 8);
|
|
||||||
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
|
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
|
||||||
(Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> {
|
(Object... params) -> ByteBuffer.allocateDirect(capacity), null, (e) -> {
|
||||||
if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false;
|
if (e == null || e.isReadOnly() || e.capacity() != capacity) return false;
|
||||||
e.clear();
|
e.clear();
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
//-----------transportChannelGroup--------------
|
//-----------transportChannelGroup--------------
|
||||||
try {
|
try {
|
||||||
|
final String strategyClass = transportConf.getValue("strategy");
|
||||||
|
if (strategyClass != null && !strategyClass.isEmpty()) {
|
||||||
|
strategy = (TransportStrategy) classLoader.loadClass(strategyClass).newInstance();
|
||||||
|
}
|
||||||
final AtomicInteger counter = new AtomicInteger();
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
@@ -228,17 +283,54 @@ public final class Application {
|
|||||||
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
|
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.transportBufferPool = transportPool;
|
if (transportGroup == null) {
|
||||||
this.transportExecutor = transportExec;
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
this.transportChannelGroup = transportGroup;
|
transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
|
||||||
|
Thread t = new Thread(r);
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.setName("Transport-Thread-" + counter.incrementAndGet());
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (transportPool == null) {
|
||||||
|
final int capacity = bufferCapacity;
|
||||||
|
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
|
||||||
|
(Object... params) -> ByteBuffer.allocateDirect(capacity), null, (e) -> {
|
||||||
|
if (e == null || e.isReadOnly() || e.capacity() != capacity) return false;
|
||||||
|
e.clear();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.sncpTransportFactory = TransportFactory.create(transportExec, transportPool, transportGroup, strategy);
|
||||||
|
DefaultAnyValue tarnsportConf = DefaultAnyValue.create(TransportFactory.NAME_PINGINTERVAL, System.getProperty("net.transport.pinginterval", "30"));
|
||||||
|
this.sncpTransportFactory.init(tarnsportConf, Sncp.PING_BUFFER, Sncp.PONG_BUFFER.remaining());
|
||||||
|
Thread.currentThread().setContextClassLoader(this.classLoader);
|
||||||
|
this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceFactory getResourceFactory() {
|
public ResourceFactory getResourceFactory() {
|
||||||
return resourceFactory;
|
return resourceFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WatchFactory getWatchFactory() {
|
public TransportFactory getSncpTransportFactory() {
|
||||||
return watchFactory;
|
return sncpTransportFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedkaleClassLoader getClassLoader() {
|
||||||
|
return classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedkaleClassLoader getServerClassLoader() {
|
||||||
|
return serverClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NodeServer> getNodeServers() {
|
||||||
|
return new ArrayList<>(servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getHome() {
|
public File getHome() {
|
||||||
@@ -249,8 +341,8 @@ public final class Application {
|
|||||||
return startTime;
|
return startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initLogging() {
|
public AnyValue getAppConfig() {
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
@@ -264,12 +356,12 @@ public final class Application {
|
|||||||
|
|
||||||
File persist = new File(this.home, "conf/persistence.xml");
|
File persist = new File(this.home, "conf/persistence.xml");
|
||||||
final String homepath = this.home.getCanonicalPath();
|
final String homepath = this.home.getCanonicalPath();
|
||||||
if (persist.isFile()) System.setProperty(DataDefaultSource.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
|
||||||
logger.log(Level.INFO, RESNAME_APP_HOME + "= " + homepath + "\r\n" + RESNAME_APP_ADDR + "= " + this.localAddress.getHostAddress());
|
logger.log(Level.INFO, "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath);
|
||||||
String lib = config.getValue("lib", "").trim().replace("${APP_HOME}", homepath);
|
String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath);
|
||||||
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
|
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
|
||||||
Server.loadLib(logger, lib);
|
Server.loadLib(classLoader, logger, lib);
|
||||||
initLogging();
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
final AnyValue resources = config.getAnyValue("resources");
|
final AnyValue resources = config.getAnyValue("resources");
|
||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
@@ -295,6 +387,7 @@ public final class Application {
|
|||||||
String name = prop.getValue("name");
|
String name = prop.getValue("name");
|
||||||
String value = prop.getValue("value");
|
String value = prop.getValue("value");
|
||||||
if (name == null || value == null) continue;
|
if (name == null || value == null) continue;
|
||||||
|
value = value.replace("${APP_HOME}", home.getCanonicalPath()).replace('\\', '/');
|
||||||
if (name.startsWith("system.property.")) {
|
if (name.startsWith("system.property.")) {
|
||||||
System.setProperty(name.substring("system.property.".length()), value);
|
System.setProperty(name.substring("system.property.".length()), value);
|
||||||
} else if (name.startsWith("mimetype.property.")) {
|
} else if (name.startsWith("mimetype.property.")) {
|
||||||
@@ -307,15 +400,75 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.localAddress != null && this.resourceFactory.find("property.datasource.nodeid", String.class) == null) {
|
|
||||||
byte[] bs = this.localAddress.getAddress();
|
|
||||||
int v = (0xff & bs[bs.length - 2]) % 10 * 100 + (0xff & bs[bs.length - 1]);
|
|
||||||
this.resourceFactory.register("property.datasource.nodeid", "" + v);
|
|
||||||
}
|
|
||||||
this.resourceFactory.register(BsonFactory.root());
|
this.resourceFactory.register(BsonFactory.root());
|
||||||
this.resourceFactory.register(JsonFactory.root());
|
this.resourceFactory.register(JsonFactory.root());
|
||||||
this.resourceFactory.register(BsonFactory.root().getConvert());
|
this.resourceFactory.register(BsonFactory.root().getConvert());
|
||||||
this.resourceFactory.register(JsonFactory.root().getConvert());
|
this.resourceFactory.register(JsonFactory.root().getConvert());
|
||||||
|
this.resourceFactory.register("bsonconvert", Convert.class, BsonFactory.root().getConvert());
|
||||||
|
this.resourceFactory.register("jsonconvert", Convert.class, JsonFactory.root().getConvert());
|
||||||
|
//只有WatchService才能加载Application、WatchFactory
|
||||||
|
final Application application = this;
|
||||||
|
this.resourceFactory.register(new ResourceFactory.ResourceLoader() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) {
|
||||||
|
try {
|
||||||
|
Resource res = field.getAnnotation(Resource.class);
|
||||||
|
if (res == null) return;
|
||||||
|
if (Sncp.isRemote((Service) src)) return; //远程模式不得注入
|
||||||
|
Class type = field.getType();
|
||||||
|
if (type == Application.class) {
|
||||||
|
field.set(src, application);
|
||||||
|
} else if (type == ResourceFactory.class) {
|
||||||
|
field.set(src, res.name().equalsIgnoreCase("server") ? rf : (res.name().isEmpty() ? application.resourceFactory : null));
|
||||||
|
} else if (type == TransportFactory.class) {
|
||||||
|
field.set(src, application.sncpTransportFactory);
|
||||||
|
} else if (type == NodeSncpServer.class) {
|
||||||
|
NodeServer server = null;
|
||||||
|
for (NodeServer ns : application.getNodeServers()) {
|
||||||
|
if (ns.getClass() == NodeSncpServer.class) continue;
|
||||||
|
if (res.name().equals(ns.server.getName())) {
|
||||||
|
server = ns;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
field.set(src, server);
|
||||||
|
} else if (type == NodeHttpServer.class) {
|
||||||
|
NodeServer server = null;
|
||||||
|
for (NodeServer ns : application.getNodeServers()) {
|
||||||
|
if (ns.getClass() == NodeHttpServer.class) continue;
|
||||||
|
if (res.name().equals(ns.server.getName())) {
|
||||||
|
server = ns;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
field.set(src, server);
|
||||||
|
} else if (type == NodeWatchServer.class) {
|
||||||
|
NodeServer server = null;
|
||||||
|
for (NodeServer ns : application.getNodeServers()) {
|
||||||
|
if (ns.getClass() == NodeWatchServer.class) continue;
|
||||||
|
if (res.name().equals(ns.server.getName())) {
|
||||||
|
server = ns;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
field.set(src, server);
|
||||||
|
}
|
||||||
|
// if (type == WatchFactory.class) {
|
||||||
|
// field.set(src, application.watchFactory);
|
||||||
|
// }
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "Resource inject error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean autoNone() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}, Application.class, ResourceFactory.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
initResources();
|
initResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,30 +477,42 @@ public final class Application {
|
|||||||
final AnyValue resources = config.getAnyValue("resources");
|
final AnyValue resources = config.getAnyValue("resources");
|
||||||
if (resources != null) {
|
if (resources != null) {
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
|
|
||||||
for (AnyValue conf : resources.getAnyValues("group")) {
|
for (AnyValue conf : resources.getAnyValues("group")) {
|
||||||
final String group = conf.getValue("name", "");
|
final String group = conf.getValue("name", "");
|
||||||
final String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase();
|
final String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase();
|
||||||
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
|
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
|
||||||
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
|
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
|
||||||
}
|
}
|
||||||
GroupInfo ginfo = globalGroups.get(group);
|
TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, conf.getValue("subprotocol", ""), new LinkedHashSet<>());
|
||||||
if (ginfo == null) {
|
|
||||||
ginfo = new GroupInfo(group, protocol, conf.getValue("kind", ""), new LinkedHashSet<>());
|
|
||||||
globalGroups.put(group, ginfo);
|
|
||||||
}
|
|
||||||
for (AnyValue node : conf.getAnyValues("node")) {
|
for (AnyValue node : conf.getAnyValues("node")) {
|
||||||
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
|
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
|
||||||
ginfo.addrs.add(addr);
|
ginfo.putAddress(addr);
|
||||||
String oldgroup = globalNodes.get(addr);
|
|
||||||
if (oldgroup != null) throw new RuntimeException(addr + " had one more group " + (globalNodes.get(addr)));
|
|
||||||
globalNodes.put(addr, group);
|
|
||||||
}
|
}
|
||||||
|
sncpTransportFactory.addGroupInfo(ginfo);
|
||||||
|
}
|
||||||
|
for (AnyValue conf : resources.getAnyValues("listener")) {
|
||||||
|
final String listenClass = conf.getValue("value", "");
|
||||||
|
if (listenClass.isEmpty()) continue;
|
||||||
|
Class clazz = Class.forName(listenClass);
|
||||||
|
if (!ApplicationListener.class.isAssignableFrom(clazz)) continue;
|
||||||
|
ApplicationListener listener = (ApplicationListener) clazz.newInstance();
|
||||||
|
listener.init(config);
|
||||||
|
this.listeners.add(listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void restoreConfig() throws IOException {
|
||||||
|
synchronized (this) {
|
||||||
|
File confFile = new File(this.home, "conf/application.xml");
|
||||||
|
confFile.renameTo(new File(this.home, "conf/application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
|
||||||
|
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
|
||||||
|
ps.append(config.toXML("application"));
|
||||||
|
ps.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void startSelfServer() throws Exception {
|
private void startSelfServer() throws Exception {
|
||||||
final Application application = this;
|
final Application application = this;
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@@ -392,7 +557,7 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
} else if ("APIDOC".equalsIgnoreCase(new String(bytes))) {
|
} else if ("APIDOC".equalsIgnoreCase(new String(bytes))) {
|
||||||
try {
|
try {
|
||||||
new ApiDocs(application).run();
|
new ApiDocsService(application).run();
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
buffer.put("APIDOC OK".getBytes());
|
buffer.put("APIDOC OK".getBytes());
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
@@ -423,13 +588,27 @@ public final class Application {
|
|||||||
channel.write(buffer);
|
channel.write(buffer);
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
channel.configureBlocking(false);
|
channel.configureBlocking(false);
|
||||||
channel.read(buffer);
|
try {
|
||||||
buffer.flip();
|
channel.read(buffer);
|
||||||
byte[] bytes = new byte[buffer.remaining()];
|
buffer.flip();
|
||||||
buffer.get(bytes);
|
byte[] bytes = new byte[buffer.remaining()];
|
||||||
channel.close();
|
buffer.get(bytes);
|
||||||
logger.info(new String(bytes));
|
channel.close();
|
||||||
Thread.sleep(500);
|
logger.info(new String(bytes));
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof PortUnreachableException) {
|
||||||
|
if ("APIDOC".equalsIgnoreCase(command)) {
|
||||||
|
final Application application = Application.create(true);
|
||||||
|
application.init();
|
||||||
|
application.start();
|
||||||
|
new ApiDocsService(application).run();
|
||||||
|
logger.info("APIDOC OK");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() throws Exception {
|
public void start() throws Exception {
|
||||||
@@ -437,23 +616,66 @@ public final class Application {
|
|||||||
CountDownLatch timecd = new CountDownLatch(entrys.length);
|
CountDownLatch timecd = new CountDownLatch(entrys.length);
|
||||||
final List<AnyValue> sncps = new ArrayList<>();
|
final List<AnyValue> sncps = new ArrayList<>();
|
||||||
final List<AnyValue> others = new ArrayList<>();
|
final List<AnyValue> others = new ArrayList<>();
|
||||||
|
final List<AnyValue> watchs = new ArrayList<>();
|
||||||
for (final AnyValue entry : entrys) {
|
for (final AnyValue entry : entrys) {
|
||||||
if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) {
|
if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) {
|
||||||
sncps.add(entry);
|
sncps.add(entry);
|
||||||
|
} else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) {
|
||||||
|
watchs.add(entry);
|
||||||
} else {
|
} else {
|
||||||
others.add(entry);
|
others.add(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//单向SNCP服务不需要对等group
|
if (watchs.size() > 1) throw new RuntimeException("Found one more WATCH Server");
|
||||||
//if (!sncps.isEmpty() && globalNodes.isEmpty()) throw new RuntimeException("found SNCP Server node but not found <group> node info.");
|
this.watching = !watchs.isEmpty();
|
||||||
|
|
||||||
runServers(timecd, sncps); //必须确保sncp都启动后再启动其他协议
|
runServers(timecd, sncps); //必须确保SNCP服务都启动后再启动其他服务
|
||||||
runServers(timecd, others);
|
runServers(timecd, others);
|
||||||
|
runServers(timecd, watchs); //必须在所有服务都启动后再启动WATCH服务
|
||||||
timecd.await();
|
timecd.await();
|
||||||
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms");
|
//if (!singletonrun) signalHandle();
|
||||||
|
if (!singletonrun) clearPersistData();
|
||||||
|
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n");
|
||||||
if (!singletonrun) this.serversLatch.await();
|
if (!singletonrun) this.serversLatch.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearPersistData() {
|
||||||
|
File cachedir = new File(home, "cache");
|
||||||
|
if (!cachedir.isDirectory()) return;
|
||||||
|
for (File file : cachedir.listFiles()) {
|
||||||
|
if (file.getName().startsWith("persist-")) file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private void signalHandle() {
|
||||||
|
// //http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html
|
||||||
|
// String[] sigs = new String[]{"HUP", "TERM", "INT", "QUIT", "KILL", "TSTP", "USR1", "USR2", "STOP"};
|
||||||
|
// List<sun.misc.Signal> list = new ArrayList<>();
|
||||||
|
// for (String sig : sigs) {
|
||||||
|
// try {
|
||||||
|
// list.add(new sun.misc.Signal(sig));
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// sun.misc.SignalHandler handler = new sun.misc.SignalHandler() {
|
||||||
|
//
|
||||||
|
// private volatile boolean runed;
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void handle(Signal sig) {
|
||||||
|
// if (runed) return;
|
||||||
|
// runed = true;
|
||||||
|
// logger.info(Application.this.getClass().getSimpleName() + " stoped\r\n");
|
||||||
|
// System.exit(0);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// for (Signal sig : list) {
|
||||||
|
// try {
|
||||||
|
// Signal.handle(sig, handler);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void runServers(CountDownLatch timecd, final List<AnyValue> serconfs) throws Exception {
|
private void runServers(CountDownLatch timecd, final List<AnyValue> serconfs) throws Exception {
|
||||||
this.servicecdl = new CountDownLatch(serconfs.size());
|
this.servicecdl = new CountDownLatch(serconfs.size());
|
||||||
@@ -477,13 +699,22 @@ public final class Application {
|
|||||||
NodeServer server = null;
|
NodeServer server = null;
|
||||||
if ("SNCP".equals(protocol)) {
|
if ("SNCP".equals(protocol)) {
|
||||||
server = NodeSncpServer.createNodeServer(Application.this, serconf);
|
server = NodeSncpServer.createNodeServer(Application.this, serconf);
|
||||||
|
} else if ("WATCH".equalsIgnoreCase(protocol)) {
|
||||||
|
DefaultAnyValue serconf2 = (DefaultAnyValue) serconf;
|
||||||
|
DefaultAnyValue rest = (DefaultAnyValue) serconf2.getAnyValue("rest");
|
||||||
|
if (rest == null) {
|
||||||
|
rest = new DefaultAnyValue();
|
||||||
|
serconf2.addValue("rest", rest);
|
||||||
|
}
|
||||||
|
rest.setValue("base", WatchServlet.class.getName());
|
||||||
|
server = new NodeWatchServer(Application.this, serconf);
|
||||||
} else if ("HTTP".equalsIgnoreCase(protocol)) {
|
} else if ("HTTP".equalsIgnoreCase(protocol)) {
|
||||||
server = new NodeHttpServer(Application.this, serconf);
|
server = new NodeHttpServer(Application.this, serconf);
|
||||||
} else {
|
} else {
|
||||||
if (!inited.get()) {
|
if (!inited.get()) {
|
||||||
synchronized (nodeClasses) {
|
synchronized (nodeClasses) {
|
||||||
if (!inited.getAndSet(true)) { //加载自定义的协议,如:SOCKS
|
if (!inited.getAndSet(true)) { //加载自定义的协议,如:SOCKS
|
||||||
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class);
|
ClassFilter profilter = new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class, (Class[]) null);
|
||||||
ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter);
|
ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter);
|
||||||
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
|
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
|
||||||
for (FilterEntry<NodeServer> entry : entrys) {
|
for (FilterEntry<NodeServer> entry : entrys) {
|
||||||
@@ -493,7 +724,9 @@ public final class Application {
|
|||||||
p = p.toUpperCase();
|
p = p.toUpperCase();
|
||||||
if ("SNCP".equals(p) || "HTTP".equals(p)) continue;
|
if ("SNCP".equals(p) || "HTTP".equals(p)) continue;
|
||||||
final Class<? extends NodeServer> old = nodeClasses.get(p);
|
final Class<? extends NodeServer> old = nodeClasses.get(p);
|
||||||
if (old != null && old != type) throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
|
if (old != null && old != type) {
|
||||||
|
throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
|
||||||
|
}
|
||||||
nodeClasses.put(p, type);
|
nodeClasses.put(p, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,6 +795,9 @@ public final class Application {
|
|||||||
application.init();
|
application.init();
|
||||||
application.startSelfServer();
|
application.startSelfServer();
|
||||||
try {
|
try {
|
||||||
|
for (ApplicationListener listener : application.listeners) {
|
||||||
|
listener.preStart(application);
|
||||||
|
}
|
||||||
application.start();
|
application.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
application.logger.log(Level.SEVERE, "Application start error", e);
|
application.logger.log(Level.SEVERE, "Application start error", e);
|
||||||
@@ -570,17 +806,6 @@ public final class Application {
|
|||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> findSncpGroups(Transport sameGroupTransport, Collection<Transport> diffGroupTransports) {
|
|
||||||
Set<String> gs = new HashSet<>();
|
|
||||||
if (sameGroupTransport != null) gs.add(sameGroupTransport.getName());
|
|
||||||
if (diffGroupTransports != null) {
|
|
||||||
for (Transport t : diffGroupTransports) {
|
|
||||||
gs.add(t.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gs;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) {
|
NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) {
|
||||||
for (NodeServer node : servers) {
|
for (NodeServer node : servers) {
|
||||||
if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) {
|
if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) {
|
||||||
@@ -590,12 +815,15 @@ public final class Application {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupInfo findGroupInfo(String group) {
|
|
||||||
if (group == null) return null;
|
|
||||||
return globalGroups.get(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void shutdown() throws Exception {
|
private void shutdown() throws Exception {
|
||||||
|
for (ApplicationListener listener : this.listeners) {
|
||||||
|
try {
|
||||||
|
listener.preShutdown(this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
servers.stream().forEach((server) -> {
|
servers.stream().forEach((server) -> {
|
||||||
try {
|
try {
|
||||||
server.shutdown();
|
server.shutdown();
|
||||||
@@ -607,26 +835,31 @@ public final class Application {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (DataSource source : dataSources) {
|
for (DataSource source : dataSources) {
|
||||||
|
if (source == null) continue;
|
||||||
try {
|
try {
|
||||||
source.getClass().getMethod("close").invoke(source);
|
source.getClass().getMethod("close").invoke(source);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.FINER, "close DataSource erroneous", e);
|
logger.log(Level.FINER, source.getClass() + " close DataSource erroneous", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (CacheSource source : cacheSources) {
|
for (CacheSource source : cacheSources) {
|
||||||
|
if (source == null) continue;
|
||||||
try {
|
try {
|
||||||
source.getClass().getMethod("close").invoke(source);
|
source.getClass().getMethod("close").invoke(source);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.FINER, "close CacheSource erroneous", e);
|
logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e);
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.transportChannelGroup != null) {
|
|
||||||
try {
|
|
||||||
this.transportChannelGroup.shutdownNow();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.FINER, "close transportChannelGroup erroneous", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.sncpTransportFactory.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int parseLenth(String value, int defValue) {
|
||||||
|
if (value == null) return defValue;
|
||||||
|
value = value.toUpperCase().replace("B", "");
|
||||||
|
if (value.endsWith("G")) return Integer.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
|
||||||
|
if (value.endsWith("M")) return Integer.decode(value.replace("M", "")) * 1024 * 1024;
|
||||||
|
if (value.endsWith("K")) return Integer.decode(value.replace("K", "")) * 1024;
|
||||||
|
return Integer.decode(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AnyValue load(final InputStream in0) {
|
private static AnyValue load(final InputStream in0) {
|
||||||
|
|||||||
45
src/org/redkale/boot/ApplicationListener.java
Normal file
45
src/org/redkale/boot/ApplicationListener.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application启动和关闭时的监听事件 <br>
|
||||||
|
* 只能通过application.xml配置
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public interface ApplicationListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化方法
|
||||||
|
*
|
||||||
|
* @param config 配置参数
|
||||||
|
*/
|
||||||
|
default void init(AnyValue config) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application 在运行start前调用
|
||||||
|
*
|
||||||
|
* @param application Application
|
||||||
|
*/
|
||||||
|
default void preStart(Application application) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application 在运行shutdown前调用
|
||||||
|
*
|
||||||
|
* @param application Application
|
||||||
|
*/
|
||||||
|
default void preShutdown(Application application) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,9 +28,9 @@ import org.redkale.util.AnyValue.DefaultAnyValue;
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class ClassFilter<T> {
|
public final class ClassFilter<T> {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName());
|
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
|
||||||
|
|
||||||
private static final boolean finer = logger.isLoggable(Level.FINER);
|
private static final boolean finer = logger.isLoggable(Level.FINER); //日志级别
|
||||||
|
|
||||||
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
|
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
|
||||||
|
|
||||||
@@ -40,6 +40,8 @@ public final class ClassFilter<T> {
|
|||||||
|
|
||||||
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
||||||
|
|
||||||
|
private Class[] excludeSuperClasses; //不符合的父类型。
|
||||||
|
|
||||||
private Class<? extends Annotation> annotationClass;//符合的注解。不为空时,扫描结果的class必须包含该注解
|
private Class<? extends Annotation> annotationClass;//符合的注解。不为空时,扫描结果的class必须包含该注解
|
||||||
|
|
||||||
private Pattern[] includePatterns; //符合的classname正则表达式
|
private Pattern[] includePatterns; //符合的classname正则表达式
|
||||||
@@ -56,18 +58,22 @@ public final class ClassFilter<T> {
|
|||||||
|
|
||||||
private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。
|
private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。
|
||||||
|
|
||||||
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass) {
|
private final ClassLoader classLoader;
|
||||||
this(annotationClass, superClass, null);
|
|
||||||
|
public ClassFilter(ClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses) {
|
||||||
|
this(classLoader, annotationClass, superClass, excludeSuperClasses, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, AnyValue conf) {
|
public ClassFilter(ClassLoader classLoader, Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) {
|
||||||
this.annotationClass = annotationClass;
|
this.annotationClass = annotationClass;
|
||||||
this.superClass = superClass;
|
this.superClass = superClass;
|
||||||
|
this.excludeSuperClasses = excludeSuperClasses;
|
||||||
this.conf = conf;
|
this.conf = conf;
|
||||||
|
this.classLoader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassFilter create(String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
|
public static ClassFilter create(Class[] excludeSuperClasses, String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
|
||||||
ClassFilter filter = new ClassFilter(null, null);
|
ClassFilter filter = new ClassFilter(null, null, null, excludeSuperClasses);
|
||||||
filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";"));
|
filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";"));
|
||||||
filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";"));
|
filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";"));
|
||||||
filter.setPrivilegeIncludes(includeValues);
|
filter.setPrivilegeIncludes(includeValues);
|
||||||
@@ -93,7 +99,11 @@ public final class ClassFilter<T> {
|
|||||||
* @return Set<FilterEntry<T>>
|
* @return Set<FilterEntry<T>>
|
||||||
*/
|
*/
|
||||||
public final Set<FilterEntry<T>> getFilterEntrys() {
|
public final Set<FilterEntry<T>> getFilterEntrys() {
|
||||||
return entrys;
|
HashSet<FilterEntry<T>> set = new HashSet<>();
|
||||||
|
set.addAll(entrys);
|
||||||
|
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterEntrys()));
|
||||||
|
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterEntrys()));
|
||||||
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,7 +112,11 @@ public final class ClassFilter<T> {
|
|||||||
* @return Set<FilterEntry<T>>
|
* @return Set<FilterEntry<T>>
|
||||||
*/
|
*/
|
||||||
public final Set<FilterEntry<T>> getFilterExpectEntrys() {
|
public final Set<FilterEntry<T>> getFilterExpectEntrys() {
|
||||||
return expectEntrys;
|
HashSet<FilterEntry<T>> set = new HashSet<>();
|
||||||
|
set.addAll(expectEntrys);
|
||||||
|
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterExpectEntrys()));
|
||||||
|
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterExpectEntrys()));
|
||||||
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,8 +126,8 @@ public final class ClassFilter<T> {
|
|||||||
*/
|
*/
|
||||||
public final Set<FilterEntry<T>> getAllFilterEntrys() {
|
public final Set<FilterEntry<T>> getAllFilterEntrys() {
|
||||||
HashSet<FilterEntry<T>> rs = new HashSet<>();
|
HashSet<FilterEntry<T>> rs = new HashSet<>();
|
||||||
rs.addAll(entrys);
|
rs.addAll(getFilterEntrys());
|
||||||
rs.addAll(expectEntrys);
|
rs.addAll(getFilterExpectEntrys());
|
||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +167,7 @@ public final class ClassFilter<T> {
|
|||||||
}
|
}
|
||||||
if (cf == null || clazzname.startsWith("sun.")) return;
|
if (cf == null || clazzname.startsWith("sun.")) return;
|
||||||
try {
|
try {
|
||||||
Class clazz = Class.forName(clazzname);
|
Class clazz = classLoader.loadClass(clazzname);
|
||||||
if (!cf.accept(property, clazz, autoscan)) return;
|
if (!cf.accept(property, clazz, autoscan)) return;
|
||||||
if (cf.conf != null) {
|
if (cf.conf != null) {
|
||||||
if (property == null) {
|
if (property == null) {
|
||||||
@@ -177,7 +191,7 @@ public final class ClassFilter<T> {
|
|||||||
} catch (Throwable cfe) {
|
} catch (Throwable cfe) {
|
||||||
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
||||||
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) {
|
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) {
|
||||||
//logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe);
|
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +261,13 @@ public final class ClassFilter<T> {
|
|||||||
public boolean accept(AnyValue property, Class clazz, boolean autoscan) {
|
public boolean accept(AnyValue property, Class clazz, boolean autoscan) {
|
||||||
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false;
|
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false;
|
||||||
if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false;
|
if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false;
|
||||||
return superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
|
boolean rs = superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
|
||||||
|
if (rs && this.excludeSuperClasses != null && this.excludeSuperClasses.length > 0) {
|
||||||
|
for (Class c : this.excludeSuperClasses) {
|
||||||
|
if (c != null && (clazz == c || c.isAssignableFrom(clazz))) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pattern[] toPattern(String[] regs) {
|
public static Pattern[] toPattern(String[] regs) {
|
||||||
@@ -269,6 +289,18 @@ public final class ClassFilter<T> {
|
|||||||
this.superClass = superClass;
|
this.superClass = superClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class getSuperClass() {
|
||||||
|
return superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class[] getExcludeSuperClasses() {
|
||||||
|
return excludeSuperClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExcludeSuperClasses(Class[] excludeSuperClasses) {
|
||||||
|
this.excludeSuperClasses = excludeSuperClasses;
|
||||||
|
}
|
||||||
|
|
||||||
public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
|
public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
|
||||||
this.annotationClass = annotationClass;
|
this.annotationClass = annotationClass;
|
||||||
}
|
}
|
||||||
@@ -293,10 +325,6 @@ public final class ClassFilter<T> {
|
|||||||
return annotationClass;
|
return annotationClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getSuperClass() {
|
|
||||||
return superClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRefused() {
|
public boolean isRefused() {
|
||||||
return refused;
|
return refused;
|
||||||
}
|
}
|
||||||
@@ -428,12 +456,12 @@ public final class ClassFilter<T> {
|
|||||||
* @throws IOException 异常
|
* @throws IOException 异常
|
||||||
*/
|
*/
|
||||||
public static void load(final File excludeFile, final String[] excludeRegs, final ClassFilter... filters) throws IOException {
|
public static void load(final File excludeFile, final String[] excludeRegs, final ClassFilter... filters) throws IOException {
|
||||||
URLClassLoader loader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
|
RedkaleClassLoader loader = (RedkaleClassLoader) Thread.currentThread().getContextClassLoader();
|
||||||
List<URL> urlfiles = new ArrayList<>(2);
|
List<URL> urlfiles = new ArrayList<>(2);
|
||||||
List<URL> urljares = new ArrayList<>(2);
|
List<URL> urljares = new ArrayList<>(2);
|
||||||
final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null;
|
final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null;
|
||||||
final Pattern[] excludePatterns = toPattern(excludeRegs);
|
final Pattern[] excludePatterns = toPattern(excludeRegs);
|
||||||
for (URL url : loader.getURLs()) {
|
for (URL url : loader.getAllURLs()) {
|
||||||
if (exurl != null && exurl.sameFile(url)) continue;
|
if (exurl != null && exurl.sameFile(url)) continue;
|
||||||
if (excludePatterns != null) {
|
if (excludePatterns != null) {
|
||||||
boolean skip = false;
|
boolean skip = false;
|
||||||
@@ -465,6 +493,12 @@ public final class ClassFilter<T> {
|
|||||||
if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) {
|
if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) {
|
||||||
String classname = entryname.substring(0, entryname.length() - 6);
|
String classname = entryname.substring(0, entryname.length() - 6);
|
||||||
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
|
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
|
||||||
|
//常见的jar跳过
|
||||||
|
if (classname.startsWith("com.mysql.")) break;
|
||||||
|
if (classname.startsWith("org.mariadb.")) break;
|
||||||
|
if (classname.startsWith("oracle.jdbc.")) break;
|
||||||
|
if (classname.startsWith("org.postgresql.")) break;
|
||||||
|
if (classname.startsWith("com.microsoft.sqlserver.")) break;
|
||||||
classes.add(classname);
|
classes.add(classname);
|
||||||
if (debug) debugstr.append(classname).append("\r\n");
|
if (debug) debugstr.append(classname).append("\r\n");
|
||||||
for (final ClassFilter filter : filters) {
|
for (final ClassFilter filter : filters) {
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.redkale.boot;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class GroupInfo {
|
|
||||||
|
|
||||||
protected String name;
|
|
||||||
|
|
||||||
protected String protocol;
|
|
||||||
|
|
||||||
protected String kind;
|
|
||||||
|
|
||||||
protected Set<InetSocketAddress> addrs;
|
|
||||||
|
|
||||||
public GroupInfo() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public GroupInfo(String name, String protocol, String kind, Set<InetSocketAddress> addrs) {
|
|
||||||
this.name = name;
|
|
||||||
this.protocol = protocol;
|
|
||||||
this.kind = kind;
|
|
||||||
this.addrs = addrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProtocol() {
|
|
||||||
return protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProtocol(String protocol) {
|
|
||||||
this.protocol = protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKind() {
|
|
||||||
return kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKind(String kind) {
|
|
||||||
this.kind = kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<InetSocketAddress> getAddrs() {
|
|
||||||
return addrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<InetSocketAddress> copyAddrs() {
|
|
||||||
return addrs == null ? null : new LinkedHashSet<>(addrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddrs(Set<InetSocketAddress> addrs) {
|
|
||||||
this.addrs = addrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -22,6 +22,7 @@ import java.util.logging.Formatter;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public class LogFileHandler extends Handler {
|
public class LogFileHandler extends Handler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,11 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.*;
|
||||||
|
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
|
||||||
import org.redkale.boot.ClassFilter.FilterEntry;
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.http.*;
|
import org.redkale.net.http.*;
|
||||||
@@ -17,6 +19,7 @@ import org.redkale.net.sncp.Sncp;
|
|||||||
import org.redkale.service.*;
|
import org.redkale.service.*;
|
||||||
import org.redkale.util.AnyValue.DefaultAnyValue;
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.watch.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP Server节点的配置Server
|
* HTTP Server节点的配置Server
|
||||||
@@ -29,7 +32,7 @@ import org.redkale.util.*;
|
|||||||
@NodeProtocol({"HTTP"})
|
@NodeProtocol({"HTTP"})
|
||||||
public class NodeHttpServer extends NodeServer {
|
public class NodeHttpServer extends NodeServer {
|
||||||
|
|
||||||
protected final boolean rest;
|
protected final boolean rest; //是否加载REST服务, 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
|
||||||
|
|
||||||
protected final HttpServer httpServer;
|
protected final HttpServer httpServer;
|
||||||
|
|
||||||
@@ -40,7 +43,11 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Server createServer(Application application, AnyValue serconf) {
|
private static Server createServer(Application application, AnyValue serconf) {
|
||||||
return new HttpServer(application.getStartTime(), application.getWatchFactory());
|
return new HttpServer(application.getStartTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpServer getHttpServer() {
|
||||||
|
return httpServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -48,22 +55,42 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
return httpServer == null ? null : httpServer.getSocketAddress();
|
return httpServer == null ? null : httpServer.getSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter<Service> createServiceClassFilter() {
|
||||||
|
return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||||
|
return createClassFilter(null, null, HttpFilter.class, new Class[]{WatchFilter.class}, null, "filters", "filter");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ClassFilter<Servlet> createServletClassFilter() {
|
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||||
return createClassFilter(null, WebServlet.class, HttpServlet.class, null, "servlets", "servlet");
|
return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
|
protected ClassFilter createOtherClassFilter() {
|
||||||
if (httpServer != null) loadHttpServlet(this.serverConf.getAnyValue("servlets"), servletFilter);
|
return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void loadService(ClassFilter serviceFilter) throws Exception {
|
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
|
||||||
super.loadService(serviceFilter);
|
super.loadService(serviceFilter, otherFilter);
|
||||||
initWebSocketService();
|
initWebSocketService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
if (httpServer != null) loadHttpServlet(servletFilter, otherFilter);
|
||||||
|
}
|
||||||
|
|
||||||
private void initWebSocketService() {
|
private void initWebSocketService() {
|
||||||
final NodeServer self = this;
|
final NodeServer self = this;
|
||||||
final ResourceFactory regFactory = application.getResourceFactory();
|
final ResourceFactory regFactory = application.getResourceFactory();
|
||||||
@@ -71,14 +98,28 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
try {
|
try {
|
||||||
if (field.getAnnotation(Resource.class) == null) return;
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
if (!(src instanceof WebSocketServlet)) return;
|
if (!(src instanceof WebSocketServlet)) return;
|
||||||
|
ResourceFactory.ResourceLoader loader = null;
|
||||||
|
ResourceFactory sncpResFactory = null;
|
||||||
|
for (NodeServer ns : application.servers) {
|
||||||
|
if (!ns.isSNCP()) continue;
|
||||||
|
sncpResFactory = ns.resourceFactory;
|
||||||
|
loader = sncpResFactory.findLoader(WebSocketNode.class, field);
|
||||||
|
if (loader != null) break;
|
||||||
|
}
|
||||||
|
if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment);
|
||||||
synchronized (regFactory) {
|
synchronized (regFactory) {
|
||||||
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
|
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
|
||||||
if (nodeService == null) {
|
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
|
||||||
nodeService = Sncp.createLocalService(resourceName, getExecutor(), application.getResourceFactory(), WebSocketNodeService.class, (InetSocketAddress) null, (Transport) null, (Collection<Transport>) null);
|
resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class));
|
||||||
regFactory.register(resourceName, WebSocketNode.class, nodeService);
|
resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class));
|
||||||
resourceFactory.inject(nodeService, self);
|
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
|
||||||
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
|
|
||||||
}
|
}
|
||||||
|
if (nodeService == null) {
|
||||||
|
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
|
||||||
|
regFactory.register(resourceName, WebSocketNode.class, nodeService);
|
||||||
|
}
|
||||||
|
resourceFactory.inject(nodeService, self);
|
||||||
|
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
|
||||||
field.set(src, nodeService);
|
field.set(src, nodeService);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -87,15 +128,42 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
}, WebSocketNode.class);
|
}, WebSocketNode.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadHttpServlet(final AnyValue servletsConf, final ClassFilter<? extends Servlet> filter) throws Exception {
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
|
||||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
final String prefix = servletsConf == null ? "" : servletsConf.getValue("path", "");
|
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
List<FilterEntry<? extends Servlet>> list = new ArrayList(filter.getFilterEntrys());
|
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||||
|
for (FilterEntry<? extends Filter> en : list) {
|
||||||
|
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) continue;
|
||||||
|
final HttpFilter filter = clazz.newInstance();
|
||||||
|
resourceFactory.inject(filter, this);
|
||||||
|
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
||||||
|
this.httpServer.addHttpFilter(filter, filterConf);
|
||||||
|
if (sb != null) sb.append(threadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter, ClassFilter<? extends WebSocket> webSocketFilter) throws Exception {
|
||||||
|
final AnyValue servletsConf = this.serverConf.getAnyValue("servlets");
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
|
String prefix0 = servletsConf == null ? "" : servletsConf.getValue("path", "");
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
||||||
|
final String prefix = prefix0;
|
||||||
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys());
|
||||||
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
|
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
|
||||||
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
|
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
|
||||||
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
|
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
|
||||||
if (ws1 == ws2) return o1.getType().getName().compareTo(o2.getType().getName());
|
if (ws1 == ws2) {
|
||||||
|
Priority p1 = o1.getType().getAnnotation(Priority.class);
|
||||||
|
Priority p2 = o2.getType().getAnnotation(Priority.class);
|
||||||
|
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
return v == 0 ? o1.getType().getName().compareTo(o2.getType().getName()) : 0;
|
||||||
|
}
|
||||||
return ws1 ? -1 : 1;
|
return ws1 ? -1 : 1;
|
||||||
});
|
});
|
||||||
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
||||||
@@ -109,13 +177,6 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
final String[] mappings = ws.value();
|
final String[] mappings = ws.value();
|
||||||
String pref = ws.repair() ? prefix : "";
|
String pref = ws.repair() ? prefix : "";
|
||||||
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
|
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
|
||||||
WebInitParam[] webparams = ws.initParams();
|
|
||||||
if (webparams.length > 0) {
|
|
||||||
if (servletConf == null) servletConf = new DefaultAnyValue();
|
|
||||||
for (WebInitParam webparam : webparams) {
|
|
||||||
servletConf.addValue(webparam.name(), webparam.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
|
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
|
||||||
if (ss != null) {
|
if (ss != null) {
|
||||||
for (int i = 0; i < mappings.length; i++) {
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
@@ -124,9 +185,9 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings));
|
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int max = 0;
|
||||||
if (ss != null && sb != null) {
|
if (ss != null && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
int max = 0;
|
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
if (as.getKey().length() > max) max = as.getKey().length();
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
}
|
}
|
||||||
@@ -138,64 +199,131 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
|
||||||
if (rest && serverConf != null) {
|
if (rest && serverConf != null) {
|
||||||
|
final List<Object> restedObjects = new ArrayList<>();
|
||||||
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
|
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
|
||||||
loadRestServlet(prefix, restConf);
|
loadRestServlet(webSocketFilter, restConf, restedObjects, sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadRestServlet(final String prefix, final AnyValue restConf) throws Exception {
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, final StringBuilder sb) throws Exception {
|
||||||
if (!rest) return;
|
if (!rest) return;
|
||||||
if (restConf == null) return; //不存在REST服务
|
if (restConf == null) return; //不存在REST服务
|
||||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
|
||||||
|
String prefix0 = restConf.getValue("path", "");
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
||||||
|
final String prefix = prefix0;
|
||||||
|
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
||||||
|
|
||||||
final Class baseServletClass = Class.forName(restConf.getValue("base", DefaultRestServlet.class.getName()));
|
|
||||||
|
|
||||||
final boolean autoload = restConf.getBoolValue("autoload", true);
|
final boolean autoload = restConf.getBoolValue("autoload", true);
|
||||||
final boolean mustsign = restConf.getBoolValue("mustsign", true); //是否只加载标记@RestService的Service类
|
{ //加载RestService
|
||||||
|
String userTypeStr = restConf.getValue("usertype");
|
||||||
|
final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr);
|
||||||
|
|
||||||
final Set<String> includeValues = new HashSet<>();
|
final Class baseServletType = this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName()));
|
||||||
final Set<String> excludeValues = new HashSet<>();
|
final Set<String> includeValues = new HashSet<>();
|
||||||
for (AnyValue item : restConf.getAnyValues("service")) {
|
final Set<String> excludeValues = new HashSet<>();
|
||||||
if (item.getBoolValue("ignore", false)) {
|
for (AnyValue item : restConf.getAnyValues("service")) {
|
||||||
excludeValues.add(item.getValue("value", ""));
|
if (item.getBoolValue("ignore", false)) {
|
||||||
} else {
|
excludeValues.add(item.getValue("value", ""));
|
||||||
includeValues.add(item.getValue("value", ""));
|
} else {
|
||||||
}
|
includeValues.add(item.getValue("value", ""));
|
||||||
}
|
|
||||||
|
|
||||||
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
|
|
||||||
|
|
||||||
super.interceptorServiceWrappers.forEach((wrapper) -> {
|
|
||||||
final Class stype = wrapper.getType();
|
|
||||||
RestService rs = (RestService) stype.getAnnotation(RestService.class);
|
|
||||||
if (rs != null && rs.ignore()) return;
|
|
||||||
if (mustsign && rs == null) return;
|
|
||||||
if (stype.getAnnotation(LocalService.class) != null && rs == null) return;
|
|
||||||
|
|
||||||
final String stypename = stype.getName();
|
|
||||||
if (!autoload && !includeValues.contains(stypename)) return;
|
|
||||||
if (!restFilter.accept(stypename)) return;
|
|
||||||
|
|
||||||
RestHttpServlet servlet = httpServer.addRestServlet(wrapper.getName(), stype, wrapper.getService(), baseServletClass, prefix, (AnyValue) null);
|
|
||||||
resourceFactory.inject(servlet, NodeHttpServer.this);
|
|
||||||
if (finest) logger.finest("Create RestServlet[resource=" + wrapper.getName() + "] = " + servlet);
|
|
||||||
if (ss != null) {
|
|
||||||
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
|
||||||
for (int i = 0; i < mappings.length; i++) {
|
|
||||||
mappings[i] = prefix + mappings[i];
|
|
||||||
}
|
}
|
||||||
if (servlet.getClass().getSimpleName().charAt(0) != '_') {
|
}
|
||||||
|
|
||||||
|
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
|
||||||
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
super.interceptorServices.forEach((service) -> {
|
||||||
|
final Class stype = Sncp.getServiceType(service);
|
||||||
|
final String name = Sncp.getResourceName(service);
|
||||||
|
RestService rs = (RestService) stype.getAnnotation(RestService.class);
|
||||||
|
if (rs == null || rs.ignore()) return;
|
||||||
|
|
||||||
|
final String stypename = stype.getName();
|
||||||
|
if (!autoload && !includeValues.contains(stypename)) return;
|
||||||
|
if (!restFilter.accept(stypename)) return;
|
||||||
|
if (restedObjects.contains(service)) {
|
||||||
|
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
restedObjects.add(service); //避免重复创建Rest对象
|
||||||
|
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
|
||||||
|
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
|
||||||
|
String prefix2 = prefix;
|
||||||
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
|
if (ws != null && !ws.repair()) prefix2 = "";
|
||||||
|
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||||
|
if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
|
||||||
|
if (ss != null) {
|
||||||
|
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||||
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
|
mappings[i] = prefix2 + mappings[i];
|
||||||
|
}
|
||||||
|
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (webSocketFilter != null) { //加载RestWebSocket
|
||||||
|
final Set<String> includeValues = new HashSet<>();
|
||||||
|
final Set<String> excludeValues = new HashSet<>();
|
||||||
|
for (AnyValue item : restConf.getAnyValues("websocket")) {
|
||||||
|
if (item.getBoolValue("ignore", false)) {
|
||||||
|
excludeValues.add(item.getValue("value", ""));
|
||||||
|
} else {
|
||||||
|
includeValues.add(item.getValue("value", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
|
||||||
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
|
||||||
|
List<FilterEntry<? extends WebSocket>> list = new ArrayList(webSocketFilter.getFilterEntrys());
|
||||||
|
for (FilterEntry<? extends WebSocket> en : list) {
|
||||||
|
Class<WebSocket> clazz = (Class<WebSocket>) en.getType();
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||||
|
logger.log(Level.FINE, clazz.getName() + " cannot abstract on rest websocket, so ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Modifier.isFinal(clazz.getModifiers())) {
|
||||||
|
logger.log(Level.FINE, clazz.getName() + " cannot final on rest websocket, so ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final Class<? extends WebSocket> stype = en.getType();
|
||||||
|
RestWebSocket rs = stype.getAnnotation(RestWebSocket.class);
|
||||||
|
if (rs == null || rs.ignore()) return;
|
||||||
|
|
||||||
|
final String stypename = stype.getName();
|
||||||
|
if (!autoload && !includeValues.contains(stypename)) return;
|
||||||
|
if (!restFilter.accept(stypename)) return;
|
||||||
|
if (restedObjects.contains(stype)) {
|
||||||
|
logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
restedObjects.add(stype); //避免重复创建Rest对象
|
||||||
|
HttpServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, prefix, en.getProperty());
|
||||||
|
if (servlet == null) return; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
|
||||||
|
String prefix2 = prefix;
|
||||||
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
|
if (ws != null && !ws.repair()) prefix2 = "";
|
||||||
|
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||||
|
if (finest) logger.finest(threadName + " " + stype.getName() + " create RestWebSocketServlet " + servlet);
|
||||||
|
if (ss != null) {
|
||||||
|
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||||
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
|
mappings[i] = prefix2 + mappings[i];
|
||||||
|
}
|
||||||
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
|
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
//输出信息
|
//输出信息
|
||||||
if (ss != null && sb != null) {
|
if (ss != null && !ss.isEmpty() && sb != null) {
|
||||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
int max = 0;
|
int max = 0;
|
||||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
@@ -209,6 +337,5 @@ public class NodeHttpServer extends NodeServer {
|
|||||||
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import org.redkale.service.Service;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* NodeServer的拦截类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -17,71 +15,24 @@ import org.redkale.service.Service;
|
|||||||
*/
|
*/
|
||||||
public class NodeInterceptor {
|
public class NodeInterceptor {
|
||||||
|
|
||||||
|
/** *
|
||||||
|
* Server.start之前调用 <br>
|
||||||
|
* NodeServer.start的部署是先执行NodeInterceptor.preStart,再执行 Server.start 方法
|
||||||
|
*
|
||||||
|
* @param server NodeServer
|
||||||
|
*/
|
||||||
public void preStart(NodeServer server) {
|
public void preStart(NodeServer server) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server.shutdown之前调用 <br>
|
||||||
|
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown,再执行 Server.sshutdown 方法
|
||||||
|
*
|
||||||
|
* @param server NodeServer
|
||||||
|
*/
|
||||||
public void preShutdown(NodeServer server) {
|
public void preShutdown(NodeServer server) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InterceptorServiceWrapper<T extends Service> {
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private Class<T> type;
|
|
||||||
|
|
||||||
private T service;
|
|
||||||
|
|
||||||
public InterceptorServiceWrapper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public InterceptorServiceWrapper(String name, Class<T> type, T service) {
|
|
||||||
this.name = name;
|
|
||||||
this.type = type;
|
|
||||||
this.service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<T> getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setType(Class<T> type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getService() {
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setService(T service) {
|
|
||||||
this.service = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int hash = 7;
|
|
||||||
hash = 97 * hash + Objects.hashCode(this.name);
|
|
||||||
hash = 97 * hash + Objects.hashCode(this.type);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) return true;
|
|
||||||
if (obj == null) return false;
|
|
||||||
if (getClass() != obj.getClass()) return false;
|
|
||||||
final InterceptorServiceWrapper<?> other = (InterceptorServiceWrapper<?>) obj;
|
|
||||||
return Objects.equals(this.name, other.name) && Objects.equals(this.type, other.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package org.redkale.boot;
|
|||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑
|
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑, 只能注解在NodeServer子类上
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -5,27 +5,29 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.*;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import java.util.stream.Collectors;
|
import javax.annotation.*;
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
import static org.redkale.boot.Application.*;
|
import static org.redkale.boot.Application.*;
|
||||||
import org.redkale.boot.ClassFilter.FilterEntry;
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.convert.bson.*;
|
||||||
|
import org.redkale.net.Filter;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.http.WebSocketNode;
|
import org.redkale.net.http.WebSocketServlet;
|
||||||
import org.redkale.net.sncp.*;
|
import org.redkale.net.sncp.*;
|
||||||
import org.redkale.service.*;
|
import org.redkale.service.*;
|
||||||
import org.redkale.source.*;
|
import org.redkale.source.*;
|
||||||
import org.redkale.util.AnyValue.DefaultAnyValue;
|
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server节点的初始化配置类
|
* Server节点的初始化配置类
|
||||||
@@ -44,15 +46,6 @@ public abstract class NodeServer {
|
|||||||
//日志输出对象
|
//日志输出对象
|
||||||
protected final Logger logger;
|
protected final Logger logger;
|
||||||
|
|
||||||
//日志是否为FINE级别
|
|
||||||
protected final boolean fine;
|
|
||||||
|
|
||||||
//日志是否为FINER级别
|
|
||||||
protected final boolean finer;
|
|
||||||
|
|
||||||
//日志是否为FINEST级别
|
|
||||||
protected final boolean finest;
|
|
||||||
|
|
||||||
//进程主类
|
//进程主类
|
||||||
protected final Application application;
|
protected final Application application;
|
||||||
|
|
||||||
@@ -62,14 +55,19 @@ public abstract class NodeServer {
|
|||||||
//当前Server对象
|
//当前Server对象
|
||||||
protected final Server server;
|
protected final Server server;
|
||||||
|
|
||||||
|
//ClassLoader
|
||||||
|
protected RedkaleClassLoader serverClassLoader;
|
||||||
|
|
||||||
|
protected final Thread serverThread;
|
||||||
|
|
||||||
//当前Server的SNCP协议的组
|
//当前Server的SNCP协议的组
|
||||||
private String sncpGroup = null;
|
protected String sncpGroup = null;
|
||||||
|
|
||||||
//SNCP服务的地址, 非SNCP为null
|
//SNCP服务的地址, 非SNCP为null
|
||||||
private InetSocketAddress sncpAddress;
|
private InetSocketAddress sncpAddress;
|
||||||
|
|
||||||
//加载Service时的处理函数
|
//加载Service时的处理函数
|
||||||
protected Consumer<ServiceWrapper> consumer;
|
protected Consumer<Service> consumer;
|
||||||
|
|
||||||
//server节点的配置
|
//server节点的配置
|
||||||
protected AnyValue serverConf;
|
protected AnyValue serverConf;
|
||||||
@@ -78,49 +76,26 @@ public abstract class NodeServer {
|
|||||||
protected NodeInterceptor interceptor;
|
protected NodeInterceptor interceptor;
|
||||||
|
|
||||||
//供interceptor使用的Service对象集合
|
//供interceptor使用的Service对象集合
|
||||||
protected final Set<NodeInterceptor.InterceptorServiceWrapper> interceptorServiceWrappers = new LinkedHashSet<>();
|
protected final Set<Service> interceptorServices = new LinkedHashSet<>();
|
||||||
|
|
||||||
//本地模式的Service对象集合
|
//本地模式的Service对象集合
|
||||||
protected final Set<ServiceWrapper> localServiceWrappers = new LinkedHashSet<>();
|
protected final Set<Service> localServices = new LinkedHashSet<>();
|
||||||
|
|
||||||
//远程模式的Service对象集合
|
//远程模式的Service对象集合
|
||||||
protected final Set<ServiceWrapper> remoteServiceWrappers = new LinkedHashSet<>();
|
protected final Set<Service> remoteServices = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
private volatile int maxClassNameLength = 0;
|
||||||
|
|
||||||
|
private volatile int maxNameLength = 0;
|
||||||
|
|
||||||
public NodeServer(Application application, Server server) {
|
public NodeServer(Application application, Server server) {
|
||||||
this.application = application;
|
this.application = application;
|
||||||
this.resourceFactory = application.getResourceFactory().createChild();
|
this.resourceFactory = application.getResourceFactory().createChild();
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.logger = Logger.getLogger(this.getClass().getSimpleName());
|
this.logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
this.fine = logger.isLoggable(Level.FINE);
|
this.serverClassLoader = new RedkaleClassLoader(application.getServerClassLoader());
|
||||||
this.finer = logger.isLoggable(Level.FINER);
|
Thread.currentThread().setContextClassLoader(this.serverClassLoader);
|
||||||
this.finest = logger.isLoggable(Level.FINEST);
|
this.serverThread = Thread.currentThread();
|
||||||
}
|
|
||||||
|
|
||||||
protected Consumer<Runnable> getExecutor() throws Exception {
|
|
||||||
if (server == null) return null;
|
|
||||||
final Field field = Server.class.getDeclaredField("context");
|
|
||||||
field.setAccessible(true);
|
|
||||||
return new Consumer<Runnable>() {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(Runnable t) {
|
|
||||||
if (context == null && server != null) {
|
|
||||||
try {
|
|
||||||
this.context = (Context) field.get(server);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Server (" + server.getSocketAddress() + ") cannot find Context", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (context == null) {
|
|
||||||
t.run();
|
|
||||||
} else {
|
|
||||||
context.submit(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) {
|
public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) {
|
||||||
@@ -134,15 +109,19 @@ public abstract class NodeServer {
|
|||||||
public void init(AnyValue config) throws Exception {
|
public void init(AnyValue config) throws Exception {
|
||||||
this.serverConf = config == null ? AnyValue.create() : config;
|
this.serverConf = config == null ? AnyValue.create() : config;
|
||||||
if (isSNCP()) { // SNCP协议
|
if (isSNCP()) { // SNCP协议
|
||||||
String host = this.serverConf.getValue("host", "0.0.0.0").replace("0.0.0.0", "");
|
String host = this.serverConf.getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0").replace("0.0.0.0", "");
|
||||||
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
|
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
|
||||||
this.sncpGroup = application.globalNodes.get(this.sncpAddress);
|
this.sncpGroup = application.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");
|
||||||
}
|
}
|
||||||
//单点服务不会有 sncpAddress、sncpGroup
|
//单点服务不会有 sncpAddress、sncpGroup
|
||||||
if (this.sncpAddress != null) this.resourceFactory.register(RESNAME_SERVER_ADDR, this.sncpAddress);
|
if (this.sncpAddress != null) {
|
||||||
if (this.sncpGroup != null) this.resourceFactory.register(RESNAME_SERVER_GROUP, this.sncpGroup);
|
this.resourceFactory.register(RESNAME_SNCP_ADDR, this.sncpAddress);
|
||||||
|
this.resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, this.sncpAddress);
|
||||||
|
this.resourceFactory.register(RESNAME_SNCP_ADDR, String.class, this.sncpAddress.getHostString() + ":" + this.sncpAddress.getPort());
|
||||||
|
}
|
||||||
|
if (this.sncpGroup != null) this.resourceFactory.register(RESNAME_SNCP_GROUP, this.sncpGroup);
|
||||||
{
|
{
|
||||||
//设置root文件夹
|
//设置root文件夹
|
||||||
String webroot = this.serverConf.getValue("root", "root");
|
String webroot = this.serverConf.getValue("root", "root");
|
||||||
@@ -155,9 +134,9 @@ public abstract class NodeServer {
|
|||||||
resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile());
|
resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile());
|
||||||
resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath());
|
resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath());
|
||||||
|
|
||||||
final String homepath = myroot.getCanonicalPath();
|
|
||||||
//加入指定的classpath
|
//加入指定的classpath
|
||||||
Server.loadLib(logger, this.serverConf.getValue("lib", "").replace("${APP_HOME}", homepath) + ";" + homepath + "/lib/*;" + homepath + "/classes");
|
Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", "").replace("${APP_HOME}", application.getHome().getPath().replace('\\', '/')));
|
||||||
|
this.serverThread.setContextClassLoader(this.serverClassLoader);
|
||||||
}
|
}
|
||||||
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
|
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
|
||||||
server.init(this.serverConf);
|
server.init(this.serverConf);
|
||||||
@@ -165,155 +144,237 @@ public abstract class NodeServer {
|
|||||||
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
|
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
|
||||||
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
||||||
if (!interceptorClass.isEmpty()) {
|
if (!interceptorClass.isEmpty()) {
|
||||||
Class clazz = Class.forName(interceptorClass);
|
Class clazz = serverClassLoader.loadClass(interceptorClass);
|
||||||
this.interceptor = (NodeInterceptor) clazz.newInstance();
|
this.interceptor = (NodeInterceptor) clazz.newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
|
||||||
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
||||||
|
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
||||||
|
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
||||||
|
ClassFilter otherFilter = createOtherClassFilter();
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
if (servletFilter == null) {
|
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter, filterFilter, servletFilter, otherFilter);
|
||||||
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter);
|
|
||||||
} else {
|
|
||||||
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter, servletFilter);
|
|
||||||
}
|
|
||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
||||||
loadService(serviceFilter); //必须在servlet之前
|
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
||||||
loadServlet(servletFilter);
|
loadFilter(filterFilter, otherFilter);
|
||||||
|
loadServlet(servletFilter, otherFilter);
|
||||||
|
|
||||||
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception;
|
protected abstract void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception;
|
||||||
|
|
||||||
|
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception;
|
||||||
|
|
||||||
private void initResource() {
|
private void initResource() {
|
||||||
final NodeServer self = this;
|
final NodeServer self = this;
|
||||||
//---------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------
|
||||||
final ResourceFactory appResFactory = application.getResourceFactory();
|
final ResourceFactory appResFactory = application.getResourceFactory();
|
||||||
|
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
|
||||||
|
final AnyValue resources = application.config.getAnyValue("resources");
|
||||||
|
final Map<String, AnyValue> cacheResource = new HashMap<>();
|
||||||
|
final Map<String, AnyValue> dataResources = new HashMap<>();
|
||||||
|
if (resources != null) {
|
||||||
|
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
||||||
|
try {
|
||||||
|
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
||||||
|
if (!Service.class.isAssignableFrom(type)) {
|
||||||
|
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
|
||||||
|
} else if (CacheSource.class.isAssignableFrom(type)) {
|
||||||
|
cacheResource.put(sourceConf.getValue("name", ""), sourceConf);
|
||||||
|
} else if (DataSource.class.isAssignableFrom(type)) {
|
||||||
|
dataResources.put(sourceConf.getValue("name", ""), sourceConf);
|
||||||
|
} else {
|
||||||
|
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "load application source resource error: " + sourceConf, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------- 注册Resource --------------------------------------------------------
|
||||||
|
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
|
||||||
|
try {
|
||||||
|
Resource res = field.getAnnotation(Resource.class);
|
||||||
|
if (res == null || !res.name().startsWith("properties.")) return;
|
||||||
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
|
||||||
|
Class type = field.getType();
|
||||||
|
if (type != AnyValue.class && type != AnyValue[].class) return;
|
||||||
|
Object resource = null;
|
||||||
|
final AnyValue properties = resources == null ? null : resources.getAnyValue("properties");
|
||||||
|
if (properties != null && type == AnyValue.class) {
|
||||||
|
resource = properties.getAnyValue(res.name().substring("properties.".length()));
|
||||||
|
appResFactory.register(resourceName, AnyValue.class, resource);
|
||||||
|
} else if (properties != null && type == AnyValue[].class) {
|
||||||
|
resource = properties.getAnyValues(res.name().substring("properties.".length()));
|
||||||
|
appResFactory.register(resourceName, AnyValue[].class, resource);
|
||||||
|
}
|
||||||
|
field.set(src, resource);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "Resource inject error", e);
|
||||||
|
}
|
||||||
|
}, AnyValue.class, AnyValue[].class);
|
||||||
|
|
||||||
|
//------------------------------------- 注册DataSource --------------------------------------------------------
|
||||||
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
|
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
|
||||||
try {
|
try {
|
||||||
if (field.getAnnotation(Resource.class) == null) return;
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
|
||||||
DataSource source = new DataDefaultSource(resourceName);
|
AnyValue sourceConf = dataResources.get(resourceName);
|
||||||
|
DataSource source = null;
|
||||||
|
boolean needinit = true;
|
||||||
|
if (sourceConf != null) {
|
||||||
|
final Class sourceType = serverClassLoader.loadClass(sourceConf.getValue("value"));
|
||||||
|
if (DataSource.class.isAssignableFrom(sourceType)) { // DataSource
|
||||||
|
final Service srcService = (Service) src;
|
||||||
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
|
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());
|
||||||
|
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (source == null) {
|
||||||
|
source = DataSources.createDataSource(resourceName); //从persistence.xml配置中创建
|
||||||
|
needinit = false;
|
||||||
|
}
|
||||||
application.dataSources.add(source);
|
application.dataSources.add(source);
|
||||||
appResFactory.register(resourceName, DataSource.class, source);
|
appResFactory.register(resourceName, DataSource.class, source);
|
||||||
|
|
||||||
SncpClient client = Sncp.getSncpClient((Service) src);
|
SncpClient client = Sncp.getSncpClient((Service) src);
|
||||||
Transport sameGroupTransport = Sncp.getSameGroupTransport((Service) src);
|
|
||||||
List<Transport> diffGroupTransports = Arrays.asList(Sncp.getDiffGroupTransports((Service) src));
|
|
||||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
|
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
|
||||||
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, DataCacheListenerService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
|
|
||||||
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
|
|
||||||
final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
|
final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
|
||||||
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
|
final Set<String> groups = new HashSet<>();
|
||||||
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpServer.getSncpGroup(), gs, null);
|
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
||||||
localServiceWrappers.add(wrapper);
|
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
||||||
sncpServer.consumerAccept(wrapper);
|
Service cacheListenerService = Sncp.createLocalService(serverClassLoader, resourceName, DataCacheListenerService.class, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf((Service) src));
|
||||||
|
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
|
||||||
|
localServices.add(cacheListenerService);
|
||||||
|
sncpServer.consumerAccept(cacheListenerService);
|
||||||
rf.inject(cacheListenerService, self);
|
rf.inject(cacheListenerService, self);
|
||||||
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
|
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + cacheListenerService);
|
||||||
}
|
}
|
||||||
field.set(src, source);
|
field.set(src, source);
|
||||||
rf.inject(source, self); // 给 "datasource.nodeid" 赋值;
|
rf.inject(source, self); // 给其可能包含@Resource的字段赋值;
|
||||||
|
//NodeServer.this.watchFactory.inject(src);
|
||||||
|
if (source instanceof Service && needinit) ((Service) source).init(sourceConf);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "DataSource inject error", e);
|
logger.log(Level.SEVERE, "DataSource inject error", e);
|
||||||
}
|
}
|
||||||
}, DataSource.class);
|
}, DataSource.class);
|
||||||
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
|
|
||||||
try {
|
|
||||||
if (field.getAnnotation(Resource.class) == null) return;
|
|
||||||
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 CacheSource
|
|
||||||
|
|
||||||
SncpClient client = Sncp.getSncpClient((Service) src);
|
//------------------------------------- 注册CacheSource --------------------------------------------------------
|
||||||
Transport sameGroupTransport = Sncp.getSameGroupTransport((Service) src);
|
resourceFactory.register(new ResourceFactory.ResourceLoader() {
|
||||||
Transport[] dts = Sncp.getDiffGroupTransports((Service) src);
|
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
|
||||||
List<Transport> diffGroupTransports = dts == null ? new ArrayList<>() : Arrays.asList(dts);
|
try {
|
||||||
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
final CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheSourceService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
|
||||||
Type genericType = field.getGenericType();
|
final Service srcService = (Service) src;
|
||||||
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
source.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class);
|
final Set<String> groups = new HashSet<>();
|
||||||
if (field.getAnnotation(Transient.class) != null) source.setNeedStore(false); //必须在setStoreType之后
|
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
|
||||||
application.cacheSources.add(source);
|
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
|
||||||
appResFactory.register(resourceName, genericType, source);
|
|
||||||
appResFactory.register(resourceName, CacheSource.class, source);
|
|
||||||
field.set(src, source);
|
|
||||||
rf.inject(source, self); //
|
|
||||||
((Service) source).init(null);
|
|
||||||
|
|
||||||
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheSourceService
|
AnyValue sourceConf = cacheResource.get(resourceName);
|
||||||
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
|
if (sourceConf == null) sourceConf = dataResources.get(resourceName);
|
||||||
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
|
final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
|
||||||
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, sncpServer.getSncpGroup(), gs, null);
|
Object source = null;
|
||||||
sncpServer.getSncpServer().addSncpServlet(wrapper);
|
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
||||||
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
|
source = (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
||||||
|
Type genericType = field.getGenericType();
|
||||||
|
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
|
||||||
|
Type valType = pt == null ? null : pt.getActualTypeArguments()[0];
|
||||||
|
if (CacheSource.class.isAssignableFrom(sourceType)) {
|
||||||
|
CacheSource cacheSource = (CacheSource) source;
|
||||||
|
cacheSource.initValueType(valType instanceof Class ? (Class) valType : Object.class);
|
||||||
|
cacheSource.initTransient(field.getAnnotation(Transient.class) != null); //必须在initValueType之后
|
||||||
|
}
|
||||||
|
application.cacheSources.add((CacheSource) source);
|
||||||
|
appResFactory.register(resourceName, genericType, source);
|
||||||
|
appResFactory.register(resourceName, CacheSource.class, source);
|
||||||
|
}
|
||||||
|
field.set(src, source);
|
||||||
|
rf.inject(source, self); //
|
||||||
|
if (source instanceof Service) ((Service) source).init(sourceConf);
|
||||||
|
|
||||||
|
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
|
||||||
|
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
|
||||||
|
sncpServer.getSncpServer().addSncpServlet((Service) source);
|
||||||
|
//logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
|
||||||
|
}
|
||||||
|
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "DataSource inject error", e);
|
||||||
}
|
}
|
||||||
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "DataSource inject error", e);
|
public boolean autoNone() {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}, CacheSource.class);
|
}, CacheSource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void loadService(ClassFilter serviceFilter) throws Exception {
|
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
|
||||||
if (serviceFilter == null) return;
|
if (serviceFilter == null) return;
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
final Set<FilterEntry<Service>> entrys = serviceFilter.getAllFilterEntrys();
|
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
|
||||||
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
|
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
|
||||||
|
final ResourceFactory appResourceFactory = application.getResourceFactory();
|
||||||
for (FilterEntry<Service> entry : entrys) { //service实现类
|
final TransportFactory appSncpTransFactory = application.getSncpTransportFactory();
|
||||||
final Class<? extends Service> type = entry.getType();
|
for (FilterEntry<? extends Service> entry : entrys) { //service实现类
|
||||||
if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过
|
final Class<? extends Service> serviceImplClass = entry.getType();
|
||||||
if (!Modifier.isPublic(type.getModifiers())) continue;
|
if (Modifier.isFinal(serviceImplClass.getModifiers())) continue; //修饰final的类跳过
|
||||||
|
if (!Modifier.isPublic(serviceImplClass.getModifiers())) continue;
|
||||||
if (entry.isExpect()) {
|
if (entry.isExpect()) {
|
||||||
if (Modifier.isAbstract(type.getModifiers())) continue; //修饰abstract的类跳过
|
if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
|
||||||
if (DataSource.class.isAssignableFrom(type)) continue;
|
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
if (CacheSource.class.isAssignableFrom(type)) continue;
|
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
if (DataCacheListener.class.isAssignableFrom(type)) continue;
|
if (DataCacheListener.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
if (WebSocketNode.class.isAssignableFrom(type)) continue;
|
//if (WebSocketNode.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
}
|
}
|
||||||
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
|
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
|
||||||
if (resourceFactory.find(entry.getName(), type) != null) { //Server加载Service时需要判断是否已经加载过了。
|
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
|
||||||
Service oldother = resourceFactory.find(entry.getName(), type);
|
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
|
||||||
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother));
|
interceptorServices.add(oldother);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
|
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
|
||||||
if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup);
|
if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup);
|
||||||
|
|
||||||
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) //非SNCP的Server,通常是单点服务
|
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !serviceImplClass.isInterface() && !Modifier.isAbstract(serviceImplClass.getModifiers())) //非SNCP的Server,通常是单点服务
|
||||||
|| groups.contains(this.sncpGroup) //本地IP含在内的
|
|| groups.contains(this.sncpGroup) //本地IP含在内的
|
||||||
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|
||||||
|| type.getAnnotation(LocalService.class) != null;//本地模式
|
|| serviceImplClass.getAnnotation(Local.class) != null;//本地模式
|
||||||
if (localed && (type.isInterface() || Modifier.isAbstract(type.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
|
if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
|
||||||
final BiConsumer<ResourceFactory, Boolean> runner = (ResourceFactory rf, Boolean needinject) -> {
|
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
|
||||||
try {
|
try {
|
||||||
Service service;
|
Service service;
|
||||||
if (localed) { //本地模式
|
boolean ws = src instanceof WebSocketServlet;
|
||||||
service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type,
|
if (ws || localed) { //本地模式
|
||||||
NodeServer.this.sncpAddress, loadTransport(NodeServer.this.sncpGroup), loadTransports(groups));
|
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
||||||
} else {
|
} else {
|
||||||
service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, NodeServer.this.sncpAddress, loadTransport(groups));
|
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
||||||
}
|
}
|
||||||
if (SncpClient.parseMethod(type).isEmpty()) return; //class没有可用的方法, 通常为BaseService
|
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) return; //class没有可用的方法且没有标记启动优先级的, 通常为BaseService
|
||||||
final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty());
|
|
||||||
for (final Class restype : wrapper.getTypes()) {
|
final Class restype = Sncp.getResourceType(service);
|
||||||
if (resourceFactory.find(wrapper.getName(), restype) == null) {
|
if (rf.find(resourceName, restype) == null) {
|
||||||
regFactory.register(wrapper.getName(), restype, wrapper.getService());
|
regFactory.register(resourceName, restype, service);
|
||||||
if (needinject) rf.inject(wrapper.getService()); //动态加载的Service也存在按需加载的注入资源
|
} else if (isSNCP() && !entry.isAutoload()) {
|
||||||
} else if (isSNCP() && !entry.isAutoload()) {
|
throw new RuntimeException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + resourceName + ", group:" + groups + ") is repeat.");
|
||||||
throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (wrapper.isRemote()) {
|
if (Sncp.isRemote(service)) {
|
||||||
remoteServiceWrappers.add(wrapper);
|
remoteServices.add(service);
|
||||||
} else {
|
} else {
|
||||||
localServiceWrappers.add(wrapper);
|
if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
|
||||||
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, service));
|
localServices.add(service);
|
||||||
if (consumer != null) consumer.accept(wrapper);
|
interceptorServices.add(service);
|
||||||
|
if (consumer != null) consumer.accept(service);
|
||||||
}
|
}
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
throw ex;
|
throw ex;
|
||||||
@@ -322,14 +383,10 @@ public abstract class NodeServer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (entry.isExpect()) {
|
if (entry.isExpect()) {
|
||||||
ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
|
ResourceType rty = entry.getType().getAnnotation(ResourceType.class);
|
||||||
runner.accept(rf, true);
|
resourceFactory.register(resourceLoader, rty == null ? entry.getType() : rty.value());
|
||||||
};
|
|
||||||
for (final Class restype : ServiceWrapper.parseTypes(entry.getType())) {
|
|
||||||
resourceFactory.register(resourceLoader, restype);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
runner.accept(resourceFactory, false);
|
resourceLoader.load(resourceFactory, null, entry.getName(), null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -339,30 +396,43 @@ public abstract class NodeServer {
|
|||||||
|
|
||||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
//---------------- inject ----------------
|
//---------------- inject ----------------
|
||||||
new ArrayList<>(localServiceWrappers).forEach(y -> {
|
new ArrayList<>(localServices).forEach(y -> {
|
||||||
resourceFactory.inject(y.getService(), NodeServer.this);
|
resourceFactory.inject(y, NodeServer.this);
|
||||||
|
calcMaxLength(y);
|
||||||
});
|
});
|
||||||
new ArrayList<>(remoteServiceWrappers).forEach(y -> {
|
new ArrayList<>(remoteServices).forEach(y -> {
|
||||||
resourceFactory.inject(y.getService(), NodeServer.this);
|
resourceFactory.inject(y, NodeServer.this);
|
||||||
|
calcMaxLength(y);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sb != null) {
|
if (sb != null) {
|
||||||
remoteServiceWrappers.forEach(y -> {
|
remoteServices.forEach(y -> {
|
||||||
sb.append(threadName).append(y.toSimpleString()).append(" load and inject").append(LINE_SEPARATOR);
|
sb.append(threadName).append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" load and inject").append(LINE_SEPARATOR);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//----------------- init -----------------
|
//----------------- init -----------------
|
||||||
List<ServiceWrapper> swlist = new ArrayList<>(localServiceWrappers);
|
List<Service> swlist = new ArrayList<>(localServices);
|
||||||
Collections.sort(swlist);
|
Collections.sort(swlist, (o1, o2) -> {
|
||||||
localServiceWrappers.clear();
|
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
||||||
localServiceWrappers.addAll(swlist);
|
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
||||||
|
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
if (v != 0) return v;
|
||||||
|
int rs = Sncp.getResourceType(o1).getName().compareTo(Sncp.getResourceType(o2).getName());
|
||||||
|
if (rs == 0) rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2));
|
||||||
|
return rs;
|
||||||
|
});
|
||||||
|
localServices.clear();
|
||||||
|
localServices.addAll(swlist);
|
||||||
|
//this.loadPersistData();
|
||||||
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
|
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
|
||||||
CountDownLatch clds = new CountDownLatch(localServiceWrappers.size());
|
CountDownLatch clds = new CountDownLatch(localServices.size());
|
||||||
localServiceWrappers.parallelStream().forEach(y -> {
|
localServices.stream().forEach(y -> {
|
||||||
try {
|
try {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
y.getService().init(y.getConf());
|
y.init(Sncp.getConf(y));
|
||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
if (slist != null) slist.add(new StringBuilder().append(threadName).append(y.toSimpleString()).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
|
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
|
||||||
|
if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
|
||||||
} finally {
|
} finally {
|
||||||
clds.countDown();
|
clds.countDown();
|
||||||
}
|
}
|
||||||
@@ -370,7 +440,6 @@ public abstract class NodeServer {
|
|||||||
clds.await();
|
clds.await();
|
||||||
if (slist != null && sb != null) {
|
if (slist != null && sb != null) {
|
||||||
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
|
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
|
||||||
Collections.sort(wlist);
|
|
||||||
for (String s : wlist) {
|
for (String s : wlist) {
|
||||||
sb.append(s);
|
sb.append(s);
|
||||||
}
|
}
|
||||||
@@ -378,76 +447,158 @@ public abstract class NodeServer {
|
|||||||
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Transport> loadTransports(final HashSet<String> groups) {
|
private void calcMaxLength(Service y) { //计算toString中的长度
|
||||||
if (groups == null) return null;
|
maxNameLength = Math.max(maxNameLength, Sncp.getResourceName(y).length());
|
||||||
final List<Transport> transports = new ArrayList<>();
|
maxClassNameLength = Math.max(maxClassNameLength, Sncp.getResourceType(y).getName().length() + 1);
|
||||||
for (String group : groups) {
|
|
||||||
if (this.sncpGroup == null || !this.sncpGroup.equals(group)) {
|
|
||||||
transports.add(loadTransport(group));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return transports;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Transport loadTransport(final HashSet<String> groups) {
|
//尚未完整实现, 先屏蔽, 单个Service在多个Server中存在的情况下进行缓存的方案还未考虑清楚
|
||||||
if (groups == null || groups.isEmpty()) return null;
|
@SuppressWarnings("unchecked")
|
||||||
final String groupid = new ArrayList<>(groups).stream().sorted().collect(Collectors.joining(";")); //按字母排列顺序
|
private void loadPersistData() throws Exception {
|
||||||
Transport transport = application.resourceFactory.find(groupid, Transport.class);
|
File home = application.getHome();
|
||||||
if (transport != null) return transport;
|
if (home == null || !home.isDirectory()) return;
|
||||||
final List<Transport> transports = new ArrayList<>();
|
File cachedir = new File(home, "cache");
|
||||||
for (String group : groups) {
|
if (!cachedir.isDirectory()) return;
|
||||||
transports.add(loadTransport(group));
|
int port = this.server.getSocketAddress().getPort();
|
||||||
}
|
final String prefix = "persist-" + port + "-";
|
||||||
Set<InetSocketAddress> addrs = new HashSet();
|
final BsonConvert convert = BsonFactory.create().skipAllIgnore(true).getConvert();
|
||||||
transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses())));
|
synchronized (this.application) {
|
||||||
Transport first = transports.get(0);
|
for (final File file : cachedir.listFiles((dir, name) -> name.startsWith(prefix))) {
|
||||||
GroupInfo ginfo = application.findGroupInfo(first.getName());
|
if (!file.getName().endsWith(".bat")) continue;
|
||||||
Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(),
|
String classAndResname = file.getName().substring(prefix.length(), file.getName().length() - 4); //去掉尾部的.bat
|
||||||
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
|
int pos = classAndResname.indexOf('-');
|
||||||
synchronized (application.resourceFactory) {
|
String servtype = pos > 0 ? classAndResname.substring(0, pos) : classAndResname;
|
||||||
transport = application.resourceFactory.find(groupid, Transport.class);
|
String resname = pos > 0 ? classAndResname.substring(pos + 1) : "";
|
||||||
if (transport == null) {
|
|
||||||
transport = newTransport;
|
|
||||||
application.resourceFactory.register(groupid, transport);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return transport;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Transport loadTransport(final String group) {
|
FileInputStream in = new FileInputStream(file);
|
||||||
if (group == null) return null;
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Transport transport;
|
int b;
|
||||||
synchronized (application.resourceFactory) {
|
while ((b = in.read()) != '\n') out.write(b);
|
||||||
transport = application.resourceFactory.find(group, Transport.class);
|
final String[] fieldNames = out.toString().split(",");
|
||||||
if (transport != null) {
|
int timeout = (int) ((System.currentTimeMillis() - file.lastModified()) / 1000);
|
||||||
if (this.sncpAddress != null && !this.sncpAddress.equals(transport.getClientAddress())) {
|
for (final Service service : this.localServices) {
|
||||||
throw new RuntimeException(transport + "repeat create on newClientAddress = " + this.sncpAddress + ", oldClientAddress = " + transport.getClientAddress());
|
if (!servtype.equals(Sncp.getResourceType(service).getName())) continue;
|
||||||
|
if (!resname.equals(Sncp.getResourceName(service))) continue;
|
||||||
|
for (final String fieldName : fieldNames) {
|
||||||
|
Field field = null;
|
||||||
|
Class clzz = service.getClass();
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
field = clzz.getDeclaredField(fieldName);
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
} while ((clzz = clzz.getSuperclass()) != Object.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object val = convert.convertFrom(field.getGenericType(), in);
|
||||||
|
Persist persist = field.getAnnotation(Persist.class);
|
||||||
|
if (persist.timeout() == 0 || persist.timeout() >= timeout) {
|
||||||
|
if (Modifier.isFinal(field.getModifiers())) {
|
||||||
|
if (Map.class.isAssignableFrom(field.getType())) {
|
||||||
|
((Map) field.get(service)).putAll((Map) val);
|
||||||
|
} else if (Collection.class.isAssignableFrom(field.getType())) {
|
||||||
|
((Collection) field.get(service)).addAll((Collection) val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field.set(service, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (in.read() != '\n') logger.log(Level.SEVERE, servtype + "'s [" + resname + "] load value error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return transport;
|
in.close();
|
||||||
}
|
}
|
||||||
GroupInfo ginfo = application.findGroupInfo(group);
|
|
||||||
Set<InetSocketAddress> addrs = ginfo.copyAddrs();
|
|
||||||
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
|
|
||||||
transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(),
|
|
||||||
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
|
|
||||||
application.resourceFactory.register(group, transport);
|
|
||||||
}
|
}
|
||||||
return transport;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//尚未完整实现, 先屏蔽
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void savePersistData() throws IOException {
|
||||||
|
File home = application.getHome();
|
||||||
|
if (home == null || !home.isDirectory()) return;
|
||||||
|
File cachedir = new File(home, "cache");
|
||||||
|
int port = this.server.getSocketAddress().getPort();
|
||||||
|
final String prefix = "persist-" + port + "-";
|
||||||
|
final BsonConvert convert = BsonFactory.create().skipAllIgnore(true).getConvert();
|
||||||
|
for (final Service service : this.localServices) {
|
||||||
|
Class clzz = service.getClass();
|
||||||
|
final Set<String> fieldNameSet = new HashSet<>();
|
||||||
|
final List<Field> fields = new ArrayList<>();
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
do {
|
||||||
|
for (Field field : clzz.getDeclaredFields()) {
|
||||||
|
if (field.getAnnotation(Persist.class) == null) continue;
|
||||||
|
if (fieldNameSet.contains(field.getName())) continue;
|
||||||
|
if (Modifier.isStatic(field.getModifiers())) throw new RuntimeException(field + " cannot static on @" + Persist.class.getName() + " in " + clzz.getName());
|
||||||
|
if (Modifier.isFinal(field.getModifiers()) && !Map.class.isAssignableFrom(field.getType()) && !Collection.class.isAssignableFrom(field.getType())) {
|
||||||
|
throw new RuntimeException(field + " cannot final on @" + Persist.class.getName() + " in " + clzz.getName());
|
||||||
|
}
|
||||||
|
fieldNameSet.add(field.getName());
|
||||||
|
field.setAccessible(true);
|
||||||
|
try {
|
||||||
|
if (field.get(service) == null) continue;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, field + " get value error", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fields.add(field);
|
||||||
|
if (sb.length() > 0) sb.append(',');
|
||||||
|
sb.append(field.getName());
|
||||||
|
}
|
||||||
|
} while ((clzz = clzz.getSuperclass()) != Object.class);
|
||||||
|
|
||||||
|
if (fields.isEmpty()) continue; //没有数据需要缓存
|
||||||
|
// synchronized (this.application.localServices) {
|
||||||
|
// if (this.application.localServices.contains(service)) continue;
|
||||||
|
// this.application.localServices.add(service);
|
||||||
|
// }
|
||||||
|
if (!cachedir.isDirectory()) cachedir.mkdirs();
|
||||||
|
String resname = Sncp.getResourceName(service);
|
||||||
|
FileOutputStream out = new FileOutputStream(new File(cachedir, prefix + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname)) + ".bat"));
|
||||||
|
out.write(sb.toString().getBytes());
|
||||||
|
out.write('\n');
|
||||||
|
for (Field field : fields) {
|
||||||
|
Object val = null;
|
||||||
|
try {
|
||||||
|
val = field.get(service);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, field + " save value error", e);
|
||||||
|
}
|
||||||
|
convert.convertTo(out, field.getGenericType(), val);
|
||||||
|
out.write('\n');
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract ClassFilter<Filter> createFilterClassFilter();
|
||||||
|
|
||||||
protected abstract ClassFilter<Servlet> createServletClassFilter();
|
protected abstract ClassFilter<Servlet> createServletClassFilter();
|
||||||
|
|
||||||
|
protected ClassFilter createOtherClassFilter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected ClassFilter<Service> createServiceClassFilter() {
|
protected ClassFilter<Service> createServiceClassFilter() {
|
||||||
return createClassFilter(this.sncpGroup, null, Service.class, Annotation.class, "services", "service");
|
return createClassFilter(this.sncpGroup, null, Service.class, (!isSNCP() && application.watching) ? null : new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref,
|
protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref,
|
||||||
Class inter, Class<? extends Annotation> ref2, String properties, String property) {
|
Class inter, Class[] excludeSuperClasses, Class<? extends Annotation> ref2, String properties, String property) {
|
||||||
ClassFilter cf = new ClassFilter(ref, inter, null);
|
ClassFilter cf = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, null);
|
||||||
if (properties == null && properties == null) return cf;
|
if (properties == null && properties == null) {
|
||||||
if (this.serverConf == null) return cf;
|
cf.setRefused(true);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
|
if (this.serverConf == null) {
|
||||||
|
cf.setRefused(true);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
AnyValue[] proplist = this.serverConf.getAnyValues(properties);
|
AnyValue[] proplist = this.serverConf.getAnyValues(properties);
|
||||||
if (proplist == null || proplist.length < 1) return cf;
|
if (proplist == null || proplist.length < 1) {
|
||||||
|
cf.setRefused(true);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
cf = null;
|
cf = null;
|
||||||
for (AnyValue list : proplist) {
|
for (AnyValue list : proplist) {
|
||||||
DefaultAnyValue prop = null;
|
DefaultAnyValue prop = null;
|
||||||
@@ -461,20 +612,20 @@ public abstract class NodeServer {
|
|||||||
prop = new AnyValue.DefaultAnyValue();
|
prop = new AnyValue.DefaultAnyValue();
|
||||||
prop.addValue("groups", sc);
|
prop.addValue("groups", sc);
|
||||||
}
|
}
|
||||||
ClassFilter filter = new ClassFilter(ref, inter, prop);
|
ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop);
|
||||||
for (AnyValue av : list.getAnyValues(property)) { // <service> 或 <servlet> 节点
|
for (AnyValue av : list.getAnyValues(property)) { // <service>、<filter>、<servlet> 节点
|
||||||
final AnyValue[] items = av.getAnyValues("property");
|
final AnyValue[] items = av.getAnyValues("property");
|
||||||
if (av instanceof DefaultAnyValue && items.length > 0) { //存在 <property>节点
|
if (av instanceof DefaultAnyValue && items.length > 0) { //存在 <property>节点
|
||||||
DefaultAnyValue dav = DefaultAnyValue.create();
|
DefaultAnyValue dav = DefaultAnyValue.create();
|
||||||
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
|
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
|
||||||
if (strings != null) { //将<service>或<servlet>节点的属性值传给dav
|
if (strings != null) { //将<service>、<filter>、<servlet>节点的属性值传给dav
|
||||||
for (AnyValue.Entry<String> en : strings) {
|
for (AnyValue.Entry<String> en : strings) {
|
||||||
dav.addValue(en.name, en.getValue());
|
dav.addValue(en.name, en.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys();
|
final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys();
|
||||||
if (anys != null) {
|
if (anys != null) {
|
||||||
for (AnyValue.Entry<AnyValue> en : anys) { //将<service>或<servlet>节点的非property属性节点传给dav
|
for (AnyValue.Entry<AnyValue> en : anys) { //将<service>、<filter>、<servlet>节点的非property属性节点传给dav
|
||||||
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
|
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -485,7 +636,9 @@ public abstract class NodeServer {
|
|||||||
dav.addValue("properties", ps);
|
dav.addValue("properties", ps);
|
||||||
av = dav;
|
av = dav;
|
||||||
}
|
}
|
||||||
filter.filter(av, av.getValue("value"), false);
|
if (!av.getBoolValue("ignore", false)) {
|
||||||
|
filter.filter(av, av.getValue("value"), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (list.getBoolValue("autoload", true)) {
|
if (list.getBoolValue("autoload", true)) {
|
||||||
String includes = list.getValue("includes", "");
|
String includes = list.getValue("includes", "");
|
||||||
@@ -508,6 +661,24 @@ public abstract class NodeServer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isWATCH() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceFactory getResourceFactory() {
|
||||||
|
return resourceFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedkaleClassLoader getServerClassLoader() {
|
||||||
|
return serverClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerClassLoader(RedkaleClassLoader serverClassLoader) {
|
||||||
|
Objects.requireNonNull(this.serverClassLoader);
|
||||||
|
this.serverClassLoader = serverClassLoader;
|
||||||
|
this.serverThread.setContextClassLoader(serverClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
public InetSocketAddress getSncpAddress() {
|
public InetSocketAddress getSncpAddress() {
|
||||||
return sncpAddress;
|
return sncpAddress;
|
||||||
}
|
}
|
||||||
@@ -532,12 +703,12 @@ public abstract class NodeServer {
|
|||||||
public void shutdown() throws IOException {
|
public void shutdown() throws IOException {
|
||||||
if (interceptor != null) interceptor.preShutdown(this);
|
if (interceptor != null) interceptor.preShutdown(this);
|
||||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
localServiceWrappers.forEach(y -> {
|
localServices.forEach(y -> {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
y.getService().destroy(y.getConf());
|
y.destroy(Sncp.getConf(y));
|
||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
if (e > 2 && sb != null) {
|
if (e > 2 && sb != null) {
|
||||||
sb.append(y.toSimpleString()).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
|
sb.append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
@@ -548,16 +719,16 @@ public abstract class NodeServer {
|
|||||||
return (T) server;
|
return (T) server;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<NodeInterceptor.InterceptorServiceWrapper> getInterceptorServiceWrappers() {
|
public Set<Service> getInterceptorServices() {
|
||||||
return new LinkedHashSet<>(interceptorServiceWrappers);
|
return new LinkedHashSet<>(interceptorServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<ServiceWrapper> getLocalServiceWrappers() {
|
public Set<Service> getLocalServices() {
|
||||||
return new LinkedHashSet<>(localServiceWrappers);
|
return new LinkedHashSet<>(localServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<ServiceWrapper> getRemoteServiceWrappers() {
|
public Set<Service> getRemoteServices() {
|
||||||
return new LinkedHashSet<>(remoteServiceWrappers);
|
return new LinkedHashSet<>(remoteServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.Level;
|
||||||
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.sncp.*;
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.service.Service;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* SNCP Server节点的配置Server
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -39,7 +44,7 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Server createServer(Application application, AnyValue serconf) {
|
private static Server createServer(Application application, AnyValue serconf) {
|
||||||
return new SncpServer(application.getStartTime(), application.getWatchFactory());
|
return new SncpServer(application.getStartTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -47,8 +52,8 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
return sncpServer == null ? null : sncpServer.getSocketAddress();
|
return sncpServer == null ? null : sncpServer.getSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consumerAccept(ServiceWrapper wrapper) {
|
public void consumerAccept(Service service) {
|
||||||
if (this.consumer != null) this.consumer.accept(wrapper);
|
if (this.consumer != null) this.consumer.accept(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,7 +81,35 @@ public class NodeSncpServer extends NodeServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
|
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
if (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||||
|
for (FilterEntry<? extends Filter> en : list) {
|
||||||
|
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) continue;
|
||||||
|
final SncpFilter filter = clazz.newInstance();
|
||||||
|
resourceFactory.inject(filter, this);
|
||||||
|
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
||||||
|
this.sncpServer.addSncpFilter(filter, filterConf);
|
||||||
|
if (sb != null) sb.append(threadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||||
|
return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
50
src/org/redkale/boot/NodeWatchServer.java
Normal file
50
src/org/redkale/boot/NodeWatchServer.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import org.redkale.net.*;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.service.Service;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
import org.redkale.watch.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@NodeProtocol({"WATCH"})
|
||||||
|
public class NodeWatchServer extends NodeHttpServer {
|
||||||
|
|
||||||
|
public NodeWatchServer(Application application, AnyValue serconf) {
|
||||||
|
super(application, serconf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter<Service> createServiceClassFilter() {
|
||||||
|
return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||||
|
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||||
|
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter createOtherClassFilter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWATCH() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
||||||
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
|
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
|
||||||
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
|
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
|
||||||
for (var k = 0; k < servlet.actions.length; k++) {
|
for (var k = 0; k < servlet.mappings.length; k++) {
|
||||||
var action = servlet.actions[k];
|
var action = servlet.mappings[k];
|
||||||
html.push(' <tr>');
|
html.push(' <tr>');
|
||||||
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
|
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
|
||||||
html.push('<td>' + action.comment + '</td>');
|
html.push('<td>' + action.comment + '</td>');
|
||||||
|
|||||||
17
src/org/redkale/boot/watch/AbstractWatchService.java
Normal file
17
src/org/redkale/boot/watch/AbstractWatchService.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import org.redkale.service.AbstractService;
|
||||||
|
import org.redkale.watch.WatchService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public abstract class AbstractWatchService extends AbstractService implements WatchService {
|
||||||
|
|
||||||
|
}
|
||||||
50
src/org/redkale/boot/watch/FilterWatchService.java
Normal file
50
src/org/redkale/boot/watch/FilterWatchService.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.*;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.service.RetResult;
|
||||||
|
import org.redkale.util.Comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "filter", catalog = "watch", repair = false)
|
||||||
|
public class FilterWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
@Comment("Filter类名不存在")
|
||||||
|
public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002;
|
||||||
|
|
||||||
|
@Comment("Filter类名不合法")
|
||||||
|
public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003;
|
||||||
|
|
||||||
|
@Comment("Filter类名已存在")
|
||||||
|
public static final int RET_FILTER_EXISTS = 1601_0004;
|
||||||
|
|
||||||
|
@Comment("Filter的JAR包不存在")
|
||||||
|
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private Application application;
|
||||||
|
|
||||||
|
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
|
||||||
|
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
|
||||||
|
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
||||||
|
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
|
||||||
|
if (filterType == null) return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
|
||||||
|
if (jar == null) return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
|
||||||
|
List<NodeServer> nodes = application.getNodeServers();
|
||||||
|
for (NodeServer node : nodes) {
|
||||||
|
if (node.getServer().containsFilter(filterType)) return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
|
||||||
|
}
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/org/redkale/boot/watch/ServerWatchService.java
Normal file
17
src/org/redkale/boot/watch/ServerWatchService.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import org.redkale.net.http.RestService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "server", catalog = "watch", repair = false)
|
||||||
|
public class ServerWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
}
|
||||||
39
src/org/redkale/boot/watch/ServiceWatchService.java
Normal file
39
src/org/redkale/boot/watch/ServiceWatchService.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.Application;
|
||||||
|
import org.redkale.net.TransportFactory;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "service", catalog = "watch", repair = false)
|
||||||
|
public class ServiceWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private Application application;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TransportFactory transportFactory;
|
||||||
|
|
||||||
|
// @RestMapping(name = "load", auth = false, comment = "动态增加Service")
|
||||||
|
// public RetResult loadService(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
|
// //待开发
|
||||||
|
// return RetResult.success();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @RestMapping(name = "stop", auth = false, comment = "动态停止Service")
|
||||||
|
// public RetResult stopService(String name, String type) {
|
||||||
|
// //待开发
|
||||||
|
// return RetResult.success();
|
||||||
|
// }
|
||||||
|
}
|
||||||
39
src/org/redkale/boot/watch/ServletWatchService.java
Normal file
39
src/org/redkale/boot/watch/ServletWatchService.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.Application;
|
||||||
|
import org.redkale.net.TransportFactory;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "servlet", catalog = "watch", repair = false)
|
||||||
|
public class ServletWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private Application application;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TransportFactory transportFactory;
|
||||||
|
//
|
||||||
|
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
|
||||||
|
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
|
// //待开发
|
||||||
|
// return RetResult.success();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @RestMapping(name = "stop", auth = false, comment = "动态停止Servlet")
|
||||||
|
// public RetResult stopServlet(String type) {
|
||||||
|
// //待开发
|
||||||
|
// return RetResult.success();
|
||||||
|
// }
|
||||||
|
}
|
||||||
26
src/org/redkale/boot/watch/SourceWatchService.java
Normal file
26
src/org/redkale/boot/watch/SourceWatchService.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.boot.watch;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.Application;
|
||||||
|
import org.redkale.net.TransportFactory;
|
||||||
|
import org.redkale.net.http.RestService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "source", catalog = "watch", repair = false)
|
||||||
|
public class SourceWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private Application application;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TransportFactory transportFactory;
|
||||||
|
|
||||||
|
}
|
||||||
138
src/org/redkale/boot/watch/TransportWatchService.java
Normal file
138
src/org/redkale/boot/watch/TransportWatchService.java
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.Application;
|
||||||
|
import org.redkale.net.*;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.service.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "transport", catalog = "watch", repair = false)
|
||||||
|
public class TransportWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
@Comment("不存在的Group节点")
|
||||||
|
public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001;
|
||||||
|
|
||||||
|
@Comment("非法的Node节点IP地址")
|
||||||
|
public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002;
|
||||||
|
|
||||||
|
@Comment("Node节点IP地址已存在")
|
||||||
|
public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private Application application;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TransportFactory transportFactory;
|
||||||
|
|
||||||
|
@RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点")
|
||||||
|
public List<TransportGroupInfo> listNodes() {
|
||||||
|
return transportFactory.getGroupInfos();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "addnode", auth = false, comment = "动态增加指定Group的Node节点")
|
||||||
|
public RetResult addNode(@RestParam(name = "group", comment = "Group节点名") final String group,
|
||||||
|
@RestParam(name = "addr", comment = "节点IP") final String addr,
|
||||||
|
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
|
||||||
|
InetSocketAddress address;
|
||||||
|
try {
|
||||||
|
address = new InetSocketAddress(addr, port);
|
||||||
|
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
|
||||||
|
channel.connect(address).get(2, TimeUnit.SECONDS); //连接超时2秒
|
||||||
|
channel.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect");
|
||||||
|
}
|
||||||
|
if (transportFactory.findGroupName(address) != null) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists");
|
||||||
|
synchronized (this) {
|
||||||
|
if (transportFactory.findGroupInfo(group) == null) {
|
||||||
|
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
|
||||||
|
}
|
||||||
|
transportFactory.addGroupInfo(group, address);
|
||||||
|
for (Service service : transportFactory.getServices()) {
|
||||||
|
if (!Sncp.isSncpDyn(service)) continue;
|
||||||
|
SncpClient client = Sncp.getSncpClient(service);
|
||||||
|
if (Sncp.isRemote(service)) {
|
||||||
|
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
||||||
|
client.getRemoteGroupTransport().addRemoteAddresses(address);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (group.equals(client.getSameGroup())) {
|
||||||
|
client.getSameGroupTransport().addRemoteAddresses(address);
|
||||||
|
}
|
||||||
|
if (client.getDiffGroups() != null && client.getDiffGroups().contains(group)) {
|
||||||
|
for (Transport transport : client.getDiffGroupTransports()) {
|
||||||
|
transport.addRemoteAddresses(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port);
|
||||||
|
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
|
||||||
|
if (group.equals(groupconf.getValue("name"))) {
|
||||||
|
((DefaultAnyValue) groupconf).addValue("node", node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
application.restoreConfig();
|
||||||
|
}
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "removenode", auth = false, comment = "动态删除指定Group的Node节点")
|
||||||
|
public RetResult removeNode(@RestParam(name = "group", comment = "Group节点名") final String group,
|
||||||
|
@RestParam(name = "addr", comment = "节点IP") final String addr,
|
||||||
|
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
|
||||||
|
if (group == null) return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
|
||||||
|
final InetSocketAddress address = new InetSocketAddress(addr, port);
|
||||||
|
if (!group.equals(transportFactory.findGroupName(address))) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")");
|
||||||
|
synchronized (this) {
|
||||||
|
if (transportFactory.findGroupInfo(group) == null) {
|
||||||
|
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
|
||||||
|
}
|
||||||
|
transportFactory.removeGroupInfo(group, address);
|
||||||
|
for (Service service : transportFactory.getServices()) {
|
||||||
|
if (!Sncp.isSncpDyn(service)) continue;
|
||||||
|
SncpClient client = Sncp.getSncpClient(service);
|
||||||
|
if (Sncp.isRemote(service)) {
|
||||||
|
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
|
||||||
|
client.getRemoteGroupTransport().removeRemoteAddresses(address);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (group.equals(client.getSameGroup())) {
|
||||||
|
client.getSameGroupTransport().removeRemoteAddresses(address);
|
||||||
|
}
|
||||||
|
if (client.getDiffGroups() != null && client.getDiffGroups().contains(group)) {
|
||||||
|
for (Transport transport : client.getDiffGroupTransports()) {
|
||||||
|
transport.removeRemoteAddresses(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
|
||||||
|
if (group.equals(groupconf.getValue("name"))) {
|
||||||
|
((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
application.restoreConfig();
|
||||||
|
}
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入Writer,JSON则不写入。
|
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入Writer,JSON则不写入。
|
||||||
@@ -35,6 +36,28 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void convertMapTo(final Writer out, final Object... values) {
|
||||||
|
if (values == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
int count = values.length - values.length % 2;
|
||||||
|
out.writeMapB(count / 2);
|
||||||
|
for (int i = 0; i < count; i += 2) {
|
||||||
|
if (i > 0) out.writeArrayMark();
|
||||||
|
this.convertTo(out, (T) values[i]);
|
||||||
|
out.writeMapMark();
|
||||||
|
Object val = values[i + 1];
|
||||||
|
if (val instanceof CompletableFuture) {
|
||||||
|
this.convertTo(out, (T) ((CompletableFuture) val).join());
|
||||||
|
} else {
|
||||||
|
this.convertTo(out, (T) val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.writeMapE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return Object.class;
|
return Object.class;
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import java.lang.reflect.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对象数组的序列化,不包含int[]、long[]这样的primitive class数组.
|
* 数组的反序列化操作类 <br>
|
||||||
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short,对于大于32767长度的数组传输会影响性能,所以没有采用int存储。
|
* 对象数组的反序列化,不包含int[]、long[]这样的primitive class数组。 <br>
|
||||||
* 支持一定程度的泛型。
|
* 支持一定程度的泛型。 <br>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ package org.redkale.convert;
|
|||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对象数组的反序列化,不包含int[]、long[]这样的primitive class数组.
|
* 数组的序列化操作类 <br>
|
||||||
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short,对于大于32767长度的数组传输会影响性能,所以没有必要采用int存储。
|
* 对象数组的序列化,不包含int[]、long[]这样的primitive class数组。 <br>
|
||||||
* 支持一定程度的泛型。
|
* 支持一定程度的泛型。 <br>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
36
src/org/redkale/convert/BinaryConvert.java
Normal file
36
src/org/redkale/convert/BinaryConvert.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二进制序列化/反序列化操作类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类
|
||||||
|
* @param <W> Writer输出的子类
|
||||||
|
*/
|
||||||
|
public abstract class BinaryConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
|
||||||
|
|
||||||
|
protected BinaryConvert(ConvertFactory<R, W> factory) {
|
||||||
|
super(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isBinary() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract byte[] convertTo(final Object value);
|
||||||
|
|
||||||
|
public abstract byte[] convertTo(final Type type, final Object value);
|
||||||
|
|
||||||
|
public abstract byte[] convertMapTo(final Object... values);
|
||||||
|
}
|
||||||
@@ -11,9 +11,8 @@ import java.lang.reflect.Type;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对象集合的反序列化.
|
* Collection的反序列化操作类 <br>
|
||||||
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short,对于大于32767长度的集合传输会影响性能,所以没有采用int存储。
|
* 支持一定程度的泛型。 <br>
|
||||||
* 支持一定程度的泛型。
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -45,6 +44,11 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
|
|||||||
this.creator = factory.loadCreator((Class) pt.getRawType());
|
this.creator = factory.loadCreator((Class) pt.getRawType());
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.decoder = factory.loadDecoder(this.componentType);
|
||||||
|
} else if(factory.isReversible()){
|
||||||
|
this.componentType = Object.class;
|
||||||
|
this.creator = factory.loadCreator(Object.class);
|
||||||
|
factory.register(type, this);
|
||||||
|
this.decoder = factory.loadDecoder(this.componentType);
|
||||||
} else {
|
} else {
|
||||||
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
|
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ import java.lang.reflect.*;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对象集合的序列化.
|
* Collection的序列化操作类 <br>
|
||||||
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short,对于大于32767长度的集合传输会影响性能,所以没有采用int存储。
|
* 支持一定程度的泛型。 <br>
|
||||||
* 支持一定程度的泛型。
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化操作类
|
* 序列化/反序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -26,4 +30,17 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
|||||||
public ConvertFactory<R, W> getFactory() {
|
public ConvertFactory<R, W> getFactory() {
|
||||||
return this.factory;
|
return this.factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract boolean isBinary();
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
||||||
|
|
||||||
|
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value);
|
||||||
|
|
||||||
|
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value);
|
||||||
|
|
||||||
|
public abstract ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import static java.lang.annotation.RetentionPolicy.*;
|
|||||||
@Documented
|
@Documented
|
||||||
@Target({METHOD, FIELD})
|
@Target({METHOD, FIELD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Repeatable(ConvertColumns.class)
|
@Repeatable(ConvertColumn.ConvertColumns.class)
|
||||||
public @interface ConvertColumn {
|
public @interface ConvertColumn {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +31,13 @@ public @interface ConvertColumn {
|
|||||||
*/
|
*/
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给字段取个序号ID,值小靠前
|
||||||
|
*
|
||||||
|
* @return 字段排序ID
|
||||||
|
*/
|
||||||
|
int index() default 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析/序列化时是否屏蔽该字段
|
* 解析/序列化时是否屏蔽该字段
|
||||||
*
|
*
|
||||||
@@ -44,4 +51,21 @@ public @interface ConvertColumn {
|
|||||||
* @return JSON or BSON or ALL
|
* @return JSON or BSON or ALL
|
||||||
*/
|
*/
|
||||||
ConvertType type() default ConvertType.ALL;
|
ConvertType type() default ConvertType.ALL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConvertColumn 的多用类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target({METHOD, FIELD})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public static @interface ConvertColumns {
|
||||||
|
|
||||||
|
ConvertColumn[] value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,15 @@ package org.redkale.convert;
|
|||||||
/**
|
/**
|
||||||
* ConvertColumn 对应的实体类
|
* ConvertColumn 对应的实体类
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public final class ConvertColumnEntry {
|
public final class ConvertColumnEntry {
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
|
||||||
private String name = "";
|
private String name = "";
|
||||||
|
|
||||||
private boolean ignore;
|
private boolean ignore;
|
||||||
@@ -25,6 +29,7 @@ public final class ConvertColumnEntry {
|
|||||||
public ConvertColumnEntry(ConvertColumn column) {
|
public ConvertColumnEntry(ConvertColumn column) {
|
||||||
if (column == null) return;
|
if (column == null) return;
|
||||||
this.name = column.name();
|
this.name = column.name();
|
||||||
|
this.index = column.index();
|
||||||
this.ignore = column.ignore();
|
this.ignore = column.ignore();
|
||||||
this.convertType = column.type();
|
this.convertType = column.type();
|
||||||
}
|
}
|
||||||
@@ -32,7 +37,7 @@ public final class ConvertColumnEntry {
|
|||||||
public ConvertColumnEntry(String name) {
|
public ConvertColumnEntry(String name) {
|
||||||
this(name, false);
|
this(name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvertColumnEntry(String name, boolean ignore) {
|
public ConvertColumnEntry(String name, boolean ignore) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.ignore = ignore;
|
this.ignore = ignore;
|
||||||
@@ -45,6 +50,13 @@ public final class ConvertColumnEntry {
|
|||||||
this.convertType = convertType;
|
this.convertType = convertType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConvertColumnEntry(String name, int index, boolean ignore, ConvertType convertType) {
|
||||||
|
this.name = name;
|
||||||
|
this.index = index;
|
||||||
|
this.ignore = ignore;
|
||||||
|
this.convertType = convertType;
|
||||||
|
}
|
||||||
|
|
||||||
public String name() {
|
public String name() {
|
||||||
return name == null ? "" : name;
|
return name == null ? "" : name;
|
||||||
}
|
}
|
||||||
@@ -69,4 +81,12 @@ public final class ConvertColumnEntry {
|
|||||||
this.convertType = convertType;
|
this.convertType = convertType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.redkale.convert;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
import static java.lang.annotation.ElementType.*;
|
|
||||||
import static java.lang.annotation.RetentionPolicy.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ConvertColumn 的多用类
|
|
||||||
*
|
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
@Inherited
|
|
||||||
@Documented
|
|
||||||
@Target({METHOD, FIELD})
|
|
||||||
@Retention(RUNTIME)
|
|
||||||
public @interface ConvertColumns {
|
|
||||||
|
|
||||||
ConvertColumn[] value();
|
|
||||||
}
|
|
||||||
@@ -10,11 +10,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于类名的别名, 类似javax.persistence.Table
|
* 用于类名的别名, 该值必须是全局唯一 <br>
|
||||||
* 该值必须是全局唯一
|
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。
|
||||||
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@Inherited
|
@Inherited
|
||||||
@@ -23,5 +24,10 @@ import java.lang.annotation.*;
|
|||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface ConvertEntity {
|
public @interface ConvertEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 别名值
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
String value();
|
String value();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 序列化自定义异常类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class ConvertException extends RuntimeException {
|
public class ConvertException extends RuntimeException {
|
||||||
|
|||||||
@@ -5,18 +5,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.math.BigInteger;
|
import java.math.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.redkale.convert.ext.InetAddressSimpledCoder.InetSocketAddressSimpledCoder;
|
import java.util.stream.*;
|
||||||
import org.redkale.convert.ext.*;
|
import org.redkale.convert.ext.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 序列化模块的工厂类,用于注册自定义的序列化类型,获取Convert
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -84,26 +88,34 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
this.register(String.class, StringSimpledCoder.instance);
|
this.register(String.class, StringSimpledCoder.instance);
|
||||||
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
||||||
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
||||||
|
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
|
||||||
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
|
||||||
|
this.register(BigDecimal.class, BigDecimalSimpledCoder.instance);
|
||||||
this.register(InetAddress.class, InetAddressSimpledCoder.instance);
|
this.register(InetAddress.class, InetAddressSimpledCoder.instance);
|
||||||
this.register(DLong.class, DLongSimpledCoder.instance);
|
this.register(DLong.class, DLongSimpledCoder.instance);
|
||||||
this.register(Class.class, TypeSimpledCoder.instance);
|
this.register(Class.class, TypeSimpledCoder.instance);
|
||||||
this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance);
|
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressSimpledCoder.instance);
|
||||||
this.register(Pattern.class, PatternSimpledCoder.instance);
|
this.register(Pattern.class, PatternSimpledCoder.instance);
|
||||||
|
this.register(File.class, FileSimpledCoder.instance);
|
||||||
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
|
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
|
||||||
this.register(URL.class, URLSimpledCoder.instance);
|
this.register(URL.class, URLSimpledCoder.instance);
|
||||||
this.register(URI.class, URISimpledCoder.instance);
|
this.register(URI.class, URISimpledCoder.instance);
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
|
this.register(ByteBuffer.class, ByteBufferSimpledCoder.instance);
|
||||||
this.register(boolean[].class, BoolArraySimpledCoder.instance);
|
this.register(boolean[].class, BoolArraySimpledCoder.instance);
|
||||||
this.register(byte[].class, ByteArraySimpledCoder.instance);
|
this.register(byte[].class, ByteArraySimpledCoder.instance);
|
||||||
this.register(short[].class, ShortArraySimpledCoder.instance);
|
this.register(short[].class, ShortArraySimpledCoder.instance);
|
||||||
this.register(char[].class, CharArraySimpledCoder.instance);
|
this.register(char[].class, CharArraySimpledCoder.instance);
|
||||||
this.register(int[].class, IntArraySimpledCoder.instance);
|
this.register(int[].class, IntArraySimpledCoder.instance);
|
||||||
|
this.register(IntStream.class, IntArraySimpledCoder.IntStreamSimpledCoder.instance);
|
||||||
this.register(long[].class, LongArraySimpledCoder.instance);
|
this.register(long[].class, LongArraySimpledCoder.instance);
|
||||||
|
this.register(LongStream.class, LongArraySimpledCoder.LongStreamSimpledCoder.instance);
|
||||||
this.register(float[].class, FloatArraySimpledCoder.instance);
|
this.register(float[].class, FloatArraySimpledCoder.instance);
|
||||||
this.register(double[].class, DoubleArraySimpledCoder.instance);
|
this.register(double[].class, DoubleArraySimpledCoder.instance);
|
||||||
|
this.register(DoubleStream.class, DoubleArraySimpledCoder.DoubleStreamSimpledCoder.instance);
|
||||||
this.register(String[].class, StringArraySimpledCoder.instance);
|
this.register(String[].class, StringArraySimpledCoder.instance);
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
|
this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class));
|
||||||
this.register(HttpCookie.class, new Creator<HttpCookie>() {
|
this.register(HttpCookie.class, new Creator<HttpCookie>() {
|
||||||
@Override
|
@Override
|
||||||
@Creator.ConstructorParameters({"name", "value"})
|
@Creator.ConstructorParameters({"name", "value"})
|
||||||
@@ -121,7 +133,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
|
|
||||||
public abstract ConvertType getConvertType();
|
public abstract ConvertType getConvertType();
|
||||||
|
|
||||||
public abstract boolean isReversible();
|
public abstract boolean isReversible(); //是否可逆的
|
||||||
|
|
||||||
public abstract ConvertFactory createChild();
|
public abstract ConvertFactory createChild();
|
||||||
|
|
||||||
@@ -181,15 +193,71 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String getEntityAlias(Class clazz) {
|
final String getEntityAlias(Class clazz) {
|
||||||
|
if (clazz == String.class) return "A";
|
||||||
|
if (clazz == int.class) return "I";
|
||||||
|
if (clazz == Integer.class) return "i";
|
||||||
|
if (clazz == long.class) return "J";
|
||||||
|
if (clazz == Long.class) return "j";
|
||||||
|
if (clazz == byte.class) return "B";
|
||||||
|
if (clazz == Byte.class) return "b";
|
||||||
|
if (clazz == boolean.class) return "Z";
|
||||||
|
if (clazz == Boolean.class) return "z";
|
||||||
|
if (clazz == short.class) return "S";
|
||||||
|
if (clazz == Short.class) return "s";
|
||||||
|
if (clazz == char.class) return "C";
|
||||||
|
if (clazz == Character.class) return "c";
|
||||||
|
if (clazz == float.class) return "F";
|
||||||
|
if (clazz == Float.class) return "f";
|
||||||
|
if (clazz == double.class) return "D";
|
||||||
|
if (clazz == Double.class) return "d";
|
||||||
|
|
||||||
|
if (clazz == String[].class) return "[A";
|
||||||
|
if (clazz == int[].class) return "[I";
|
||||||
|
if (clazz == long[].class) return "[J";
|
||||||
|
if (clazz == byte[].class) return "[B";
|
||||||
|
if (clazz == boolean[].class) return "[Z";
|
||||||
|
if (clazz == short[].class) return "[S";
|
||||||
|
if (clazz == char[].class) return "[C";
|
||||||
|
if (clazz == float[].class) return "[F";
|
||||||
|
if (clazz == double[].class) return "[D";
|
||||||
|
|
||||||
ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class);
|
ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class);
|
||||||
if (ce != null && findEntityAlias(ce.value()) == null) entitys.put(ce.value(), clazz);
|
if (ce != null && findEntityAlias(ce.value()) == null) entitys.put(ce.value(), clazz);
|
||||||
return ce == null ? clazz.getName() : ce.value();
|
return ce == null ? clazz.getName() : ce.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Class getEntityAlias(String name) {
|
final Class getEntityAlias(String name) {
|
||||||
|
if ("A".equals(name)) return String.class;
|
||||||
|
if ("I".equals(name)) return int.class;
|
||||||
|
if ("i".equals(name)) return Integer.class;
|
||||||
|
if ("J".equals(name)) return long.class;
|
||||||
|
if ("j".equals(name)) return Long.class;
|
||||||
|
if ("B".equals(name)) return byte.class;
|
||||||
|
if ("b".equals(name)) return Byte.class;
|
||||||
|
if ("Z".equals(name)) return boolean.class;
|
||||||
|
if ("z".equals(name)) return Boolean.class;
|
||||||
|
if ("S".equals(name)) return short.class;
|
||||||
|
if ("s".equals(name)) return Short.class;
|
||||||
|
if ("C".equals(name)) return char.class;
|
||||||
|
if ("c".equals(name)) return Character.class;
|
||||||
|
if ("F".equals(name)) return float.class;
|
||||||
|
if ("f".equals(name)) return Float.class;
|
||||||
|
if ("D".equals(name)) return double.class;
|
||||||
|
if ("d".equals(name)) return Double.class;
|
||||||
|
|
||||||
|
if ("[A".equals(name)) return String[].class;
|
||||||
|
if ("[I".equals(name)) return int[].class;
|
||||||
|
if ("[J".equals(name)) return long[].class;
|
||||||
|
if ("[B".equals(name)) return byte[].class;
|
||||||
|
if ("[Z".equals(name)) return boolean[].class;
|
||||||
|
if ("[S".equals(name)) return short[].class;
|
||||||
|
if ("[C".equals(name)) return char[].class;
|
||||||
|
if ("[F".equals(name)) return float[].class;
|
||||||
|
if ("[D".equals(name)) return double[].class;
|
||||||
|
|
||||||
Class clazz = findEntityAlias(name);
|
Class clazz = findEntityAlias(name);
|
||||||
try {
|
try {
|
||||||
return clazz == null ? Class.forName(name) : clazz;
|
return clazz == null ? Thread.currentThread().getContextClassLoader().loadClass(name) : clazz;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new ConvertException("convert entity is " + name, ex);
|
throw new ConvertException("convert entity is " + name, ex);
|
||||||
}
|
}
|
||||||
@@ -390,6 +458,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
decoder = new ArrayDecoder(this, type);
|
decoder = new ArrayDecoder(this, type);
|
||||||
} else if (Collection.class.isAssignableFrom(clazz)) {
|
} else if (Collection.class.isAssignableFrom(clazz)) {
|
||||||
decoder = new CollectionDecoder(this, type);
|
decoder = new CollectionDecoder(this, type);
|
||||||
|
} else if (Stream.class.isAssignableFrom(clazz)) {
|
||||||
|
decoder = new StreamDecoder(this, type);
|
||||||
} else if (Map.class.isAssignableFrom(clazz)) {
|
} else if (Map.class.isAssignableFrom(clazz)) {
|
||||||
decoder = new MapDecoder(this, type);
|
decoder = new MapDecoder(this, type);
|
||||||
} else if (clazz == Object.class) {
|
} else if (clazz == Object.class) {
|
||||||
@@ -473,6 +543,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
encoder = new ArrayEncoder(this, type);
|
encoder = new ArrayEncoder(this, type);
|
||||||
} else if (Collection.class.isAssignableFrom(clazz)) {
|
} else if (Collection.class.isAssignableFrom(clazz)) {
|
||||||
encoder = new CollectionEncoder(this, type);
|
encoder = new CollectionEncoder(this, type);
|
||||||
|
} else if (Stream.class.isAssignableFrom(clazz)) {
|
||||||
|
encoder = new StreamEncoder(this, type);
|
||||||
} else if (Map.class.isAssignableFrom(clazz)) {
|
} else if (Map.class.isAssignableFrom(clazz)) {
|
||||||
encoder = new MapEncoder(this, type);
|
encoder = new MapEncoder(this, type);
|
||||||
} else if (clazz == Object.class) {
|
} else if (clazz == Object.class) {
|
||||||
|
|||||||
25
src/org/redkale/convert/ConvertMask.java
Normal file
25
src/org/redkale/convert/ConvertMask.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask接口
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public interface ConvertMask {
|
||||||
|
|
||||||
|
default byte mask(byte value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
default byte unmask(byte value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,11 @@
|
|||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 序列化类型枚举,结合@ConvertColumn使用
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public enum ConvertType {
|
public enum ConvertType {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.lang.reflect.*;
|
|||||||
import org.redkale.util.Attribute;
|
import org.redkale.util.Attribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 字段的反序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -21,6 +22,8 @@ import org.redkale.util.Attribute;
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class DeMember<R extends Reader, T, F> implements Comparable<DeMember<R, T, F>> {
|
public final class DeMember<R extends Reader, T, F> implements Comparable<DeMember<R, T, F>> {
|
||||||
|
|
||||||
|
protected int index;
|
||||||
|
|
||||||
protected final Attribute<T, F> attribute;
|
protected final Attribute<T, F> attribute;
|
||||||
|
|
||||||
protected Decodeable<R, F> decoder;
|
protected Decodeable<R, F> decoder;
|
||||||
@@ -67,9 +70,14 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
|
|||||||
return this.attribute;
|
return this.attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return this.index;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int compareTo(DeMember<R, T, F> o) {
|
public final int compareTo(DeMember<R, T, F> o) {
|
||||||
if (o == null) return 1;
|
if (o == null) return -1;
|
||||||
|
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
|
||||||
return this.attribute.field().compareTo(o.attribute.field());
|
return this.attribute.field().compareTo(o.attribute.field());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.redkale.convert;
|
|||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 反序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.lang.reflect.*;
|
|||||||
import org.redkale.util.Attribute;
|
import org.redkale.util.Attribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 字段的序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -30,6 +31,8 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
|
|||||||
//final boolean isnumber;
|
//final boolean isnumber;
|
||||||
final boolean isbool;
|
final boolean isbool;
|
||||||
|
|
||||||
|
protected int index;
|
||||||
|
|
||||||
public EnMember(Attribute<T, F> attribute, Encodeable<W, F> encoder) {
|
public EnMember(Attribute<T, F> attribute, Encodeable<W, F> encoder) {
|
||||||
this.attribute = attribute;
|
this.attribute = attribute;
|
||||||
this.encoder = encoder;
|
this.encoder = encoder;
|
||||||
@@ -60,9 +63,14 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
|
|||||||
return attribute.field().equals(name);
|
return attribute.field().equals(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return this.index;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int compareTo(EnMember<W, T, F> o) {
|
public final int compareTo(EnMember<W, T, F> o) {
|
||||||
if (o == null) return 1;
|
if (o == null) return -1;
|
||||||
|
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
|
||||||
return this.attribute.field().compareTo(o.attribute.field());
|
return this.attribute.field().compareTo(o.attribute.field());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.redkale.convert;
|
|||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.lang.reflect.Type;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Map的反序列化操作类 <br>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -49,6 +50,12 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
|
|||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.keyDecoder = factory.loadDecoder(this.keyType);
|
this.keyDecoder = factory.loadDecoder(this.keyType);
|
||||||
this.valueDecoder = factory.loadDecoder(this.valueType);
|
this.valueDecoder = factory.loadDecoder(this.valueType);
|
||||||
|
} else if (factory.isReversible()) {
|
||||||
|
this.keyType = Object.class;
|
||||||
|
this.valueType = Object.class;
|
||||||
|
this.creator = factory.loadCreator((Class) type);
|
||||||
|
this.keyDecoder = factory.loadDecoder(this.keyType);
|
||||||
|
this.valueDecoder = factory.loadDecoder(this.valueType);
|
||||||
} else {
|
} else {
|
||||||
throw new ConvertException("mapdecoder not support the type (" + type + ")");
|
throw new ConvertException("mapdecoder not support the type (" + type + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.lang.reflect.Type;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Map的序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import java.util.Set;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 自定义对象的反序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -66,6 +67,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
|
|||||||
clazz = (Class) type;
|
clazz = (Class) type;
|
||||||
}
|
}
|
||||||
this.creator = factory.loadCreator(clazz);
|
this.creator = factory.loadCreator(clazz);
|
||||||
|
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
|
||||||
|
|
||||||
final Set<DeMember> list = new HashSet();
|
final Set<DeMember> list = new HashSet();
|
||||||
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
|
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
|
||||||
@@ -75,8 +77,10 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
|
|||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Type t = ObjectEncoder.createClassType(field.getGenericType(), this.type);
|
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
|
||||||
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t)));
|
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t));
|
||||||
|
if (ref != null) member.index = ref.getIndex();
|
||||||
|
list.add(member);
|
||||||
}
|
}
|
||||||
final boolean reversible = factory.isReversible();
|
final boolean reversible = factory.isReversible();
|
||||||
for (final Method method : clazz.getMethods()) {
|
for (final Method method : clazz.getMethods()) {
|
||||||
@@ -85,6 +89,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
|
|||||||
if (method.isSynthetic()) continue;
|
if (method.isSynthetic()) continue;
|
||||||
if (method.getName().length() < 4) continue;
|
if (method.getName().length() < 4) continue;
|
||||||
if (!method.getName().startsWith("set")) continue;
|
if (!method.getName().startsWith("set")) continue;
|
||||||
|
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
|
||||||
if (method.getParameterTypes().length != 1) continue;
|
if (method.getParameterTypes().length != 1) continue;
|
||||||
if (method.getReturnType() != void.class) continue;
|
if (method.getReturnType() != void.class) continue;
|
||||||
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
|
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
|
||||||
@@ -97,8 +102,10 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
|
|||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Type t = ObjectEncoder.createClassType(method.getGenericParameterTypes()[0], this.type);
|
Type t = TypeToken.createClassType(method.getGenericParameterTypes()[0], this.type);
|
||||||
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t)));
|
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t));
|
||||||
|
if (ref != null) member.index = ref.getIndex();
|
||||||
|
list.add(member);
|
||||||
}
|
}
|
||||||
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
|
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
|
||||||
for (final String constructorField : cps) {
|
for (final String constructorField : cps) {
|
||||||
@@ -113,7 +120,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
|
|||||||
//不存在setter方法
|
//不存在setter方法
|
||||||
try {
|
try {
|
||||||
Field f = clazz.getDeclaredField(constructorField);
|
Field f = clazz.getDeclaredField(constructorField);
|
||||||
Type t = ObjectEncoder.createClassType(f.getGenericType(), this.type);
|
Type t = TypeToken.createClassType(f.getGenericType(), this.type);
|
||||||
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t)));
|
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t)));
|
||||||
} catch (NoSuchFieldException nsfe) { //不存在field, 可能存在getter方法
|
} catch (NoSuchFieldException nsfe) { //不存在field, 可能存在getter方法
|
||||||
char[] fs = constructorField.toCharArray();
|
char[] fs = constructorField.toCharArray();
|
||||||
@@ -125,7 +132,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
|
|||||||
} catch (NoSuchMethodException ex) {
|
} catch (NoSuchMethodException ex) {
|
||||||
getter = clazz.getMethod("is" + mn);
|
getter = clazz.getMethod("is" + mn);
|
||||||
}
|
}
|
||||||
Type t = ObjectEncoder.createClassType(getter.getGenericParameterTypes()[0], this.type);
|
Type t = TypeToken.createClassType(getter.getGenericParameterTypes()[0], this.type);
|
||||||
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
|
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.util.*;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 自定义对象的序列化操作类
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -67,8 +68,10 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
|
|||||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
ref = factory.findRef(field);
|
ref = factory.findRef(field);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Type t = createClassType(field.getGenericType(), this.type);
|
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
|
||||||
list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t)));
|
EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t));
|
||||||
|
if (ref != null) member.index = ref.getIndex();
|
||||||
|
list.add(member);
|
||||||
}
|
}
|
||||||
for (final Method method : clazz.getMethods()) {
|
for (final Method method : clazz.getMethods()) {
|
||||||
if (Modifier.isStatic(method.getModifiers())) continue;
|
if (Modifier.isStatic(method.getModifiers())) continue;
|
||||||
@@ -77,6 +80,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
|
|||||||
if (method.getName().length() < 3) continue;
|
if (method.getName().length() < 3) continue;
|
||||||
if (method.getName().equals("getClass")) continue;
|
if (method.getName().equals("getClass")) continue;
|
||||||
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue;
|
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue;
|
||||||
|
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
|
||||||
if (method.getParameterTypes().length != 0) continue;
|
if (method.getParameterTypes().length != 0) continue;
|
||||||
if (method.getReturnType() == void.class) continue;
|
if (method.getReturnType() == void.class) continue;
|
||||||
if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
|
if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
|
||||||
@@ -89,8 +93,10 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
|
|||||||
}
|
}
|
||||||
ref = factory.findRef(method);
|
ref = factory.findRef(method);
|
||||||
if (ref != null && ref.ignore()) continue;
|
if (ref != null && ref.ignore()) continue;
|
||||||
Type t = createClassType(method.getGenericReturnType(), this.type);
|
Type t = TypeToken.createClassType(method.getGenericReturnType(), this.type);
|
||||||
list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t)));
|
EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t));
|
||||||
|
if (ref != null) member.index = ref.getIndex();
|
||||||
|
list.add(member);
|
||||||
}
|
}
|
||||||
this.members = list.toArray(new EnMember[list.size()]);
|
this.members = list.toArray(new EnMember[list.size()]);
|
||||||
Arrays.sort(this.members);
|
Arrays.sort(this.members);
|
||||||
@@ -144,42 +150,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
|
|||||||
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
|
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type createClassType(final Type type, final Type declaringType0) {
|
|
||||||
if (TypeToken.isClassType(type)) return type;
|
|
||||||
if (type instanceof ParameterizedType) { // e.g. Map<String, String>
|
|
||||||
final ParameterizedType pt = (ParameterizedType) type;
|
|
||||||
final Type[] paramTypes = pt.getActualTypeArguments();
|
|
||||||
for (int i = 0; i < paramTypes.length; i++) {
|
|
||||||
paramTypes[i] = createClassType(paramTypes[i], declaringType0);
|
|
||||||
}
|
|
||||||
return TypeToken.createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes);
|
|
||||||
}
|
|
||||||
Type declaringType = declaringType0;
|
|
||||||
if (declaringType instanceof Class) {
|
|
||||||
do {
|
|
||||||
declaringType = ((Class) declaringType).getGenericSuperclass();
|
|
||||||
if (declaringType == Object.class) return Object.class;
|
|
||||||
} while (declaringType instanceof Class);
|
|
||||||
}
|
|
||||||
//存在通配符则declaringType 必须是 ParameterizedType
|
|
||||||
if (!(declaringType instanceof ParameterizedType)) return Object.class;
|
|
||||||
final ParameterizedType declaringPType = (ParameterizedType) declaringType;
|
|
||||||
final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters();
|
|
||||||
final Type[] desTypes = declaringPType.getActualTypeArguments();
|
|
||||||
if (type instanceof WildcardType) { // e.g. <? extends Serializable>
|
|
||||||
final WildcardType wt = (WildcardType) type;
|
|
||||||
for (Type f : wt.getUpperBounds()) {
|
|
||||||
for (int i = 0; i < virTypes.length; i++) {
|
|
||||||
if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
|
|
||||||
for (int i = 0; i < virTypes.length; i++) {
|
|
||||||
if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
|
// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
|
||||||
// if (type instanceof Class) { //e.g. String
|
// if (type instanceof Class) { //e.g. String
|
||||||
@@ -228,7 +198,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
|
|||||||
// }
|
// }
|
||||||
// return type;
|
// return type;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
static boolean contains(String[] values, String value) {
|
static boolean contains(String[] values, String value) {
|
||||||
for (String str : values) {
|
for (String str : values) {
|
||||||
if (str.equals(value)) return true;
|
if (str.equals(value)) return true;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 反序列化的数据读取流
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -42,6 +43,7 @@ public abstract class Reader {
|
|||||||
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
* 读取对象的类名, 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
||||||
*
|
*
|
||||||
* @param clazz 类名
|
* @param clazz 类名
|
||||||
|
*
|
||||||
* @return 返回字段数
|
* @return 返回字段数
|
||||||
*/
|
*/
|
||||||
public String readObjectB(final Class clazz) {
|
public String readObjectB(final Class clazz) {
|
||||||
@@ -86,6 +88,7 @@ public abstract class Reader {
|
|||||||
* 根据字段读取字段对应的DeMember
|
* 根据字段读取字段对应的DeMember
|
||||||
*
|
*
|
||||||
* @param members DeMember的全量集合
|
* @param members DeMember的全量集合
|
||||||
|
*
|
||||||
* @return 匹配的DeMember
|
* @return 匹配的DeMember
|
||||||
*/
|
*/
|
||||||
public abstract DeMember readFieldName(final DeMember[] members);
|
public abstract DeMember readFieldName(final DeMember[] members);
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import java.lang.reflect.ParameterizedType;
|
|||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 简易类的序列化和反序列化操作类 <br>
|
||||||
|
* 能序列化为Boolean、Number或者字符串的类视为简易类 <br>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
94
src/org/redkale/convert/StreamDecoder.java
Normal file
94
src/org/redkale/convert/StreamDecoder.java
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import org.redkale.util.Creator;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream的反序列化操作类 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的集合元素类型
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
|
||||||
|
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
|
private final Type componentType;
|
||||||
|
|
||||||
|
protected Creator<Stream<T>> creator;
|
||||||
|
|
||||||
|
protected final Decodeable<Reader, T> decoder;
|
||||||
|
|
||||||
|
private boolean inited = false;
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
public StreamDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
this.type = type;
|
||||||
|
try {
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
final ParameterizedType pt = (ParameterizedType) type;
|
||||||
|
this.componentType = pt.getActualTypeArguments()[0];
|
||||||
|
this.creator = factory.loadCreator((Class) pt.getRawType());
|
||||||
|
factory.register(type, this);
|
||||||
|
this.decoder = factory.loadDecoder(this.componentType);
|
||||||
|
} else {
|
||||||
|
throw new ConvertException("StreamDecoder not support the type (" + type + ")");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inited = true;
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<T> convertFrom(Reader in) {
|
||||||
|
final int len = in.readArrayB();
|
||||||
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
|
if (this.decoder == null) {
|
||||||
|
if (!this.inited) {
|
||||||
|
synchronized (lock) {
|
||||||
|
try {
|
||||||
|
lock.wait();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Decodeable<Reader, T> localdecoder = this.decoder;
|
||||||
|
final List<T> result = new ArrayList();
|
||||||
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
|
while (in.hasNext()) {
|
||||||
|
result.add(localdecoder.convertFrom(in));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
result.add(localdecoder.convertFrom(in));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.readArrayE();
|
||||||
|
return result.stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
90
src/org/redkale/convert/StreamEncoder.java
Normal file
90
src/org/redkale/convert/StreamEncoder.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream的序列化操作类 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 序列化的集合元素类型
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
|
||||||
|
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
|
private final Encodeable<Writer, Object> encoder;
|
||||||
|
|
||||||
|
private boolean inited = false;
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
public StreamEncoder(final ConvertFactory factory, final Type type) {
|
||||||
|
this.type = type;
|
||||||
|
try {
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
|
if (t instanceof TypeVariable) {
|
||||||
|
this.encoder = factory.getAnyEncoder();
|
||||||
|
} else {
|
||||||
|
this.encoder = factory.loadEncoder(t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.encoder = factory.getAnyEncoder();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inited = true;
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(Writer out, Stream<T> value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object[] array = value.toArray();
|
||||||
|
if (array.length == 0) {
|
||||||
|
out.writeArrayB(0);
|
||||||
|
out.writeArrayE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.encoder == null) {
|
||||||
|
if (!this.inited) {
|
||||||
|
synchronized (lock) {
|
||||||
|
try {
|
||||||
|
lock.wait();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.writeArrayB(array.length);
|
||||||
|
boolean first = true;
|
||||||
|
for (Object v : array) {
|
||||||
|
if (!first) out.writeArrayMark();
|
||||||
|
encoder.convertTo(out, v);
|
||||||
|
if (first) first = false;
|
||||||
|
}
|
||||||
|
out.writeArrayE();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/org/redkale/convert/TextConvert.java
Normal file
36
src/org/redkale/convert/TextConvert.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本序列化/反序列化操作类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类
|
||||||
|
* @param <W> Writer输出的子类
|
||||||
|
*/
|
||||||
|
public abstract class TextConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
|
||||||
|
|
||||||
|
protected TextConvert(ConvertFactory<R, W> factory) {
|
||||||
|
super(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isBinary() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String convertTo(final Object value);
|
||||||
|
|
||||||
|
public abstract String convertTo(final Type type, final Object value);
|
||||||
|
|
||||||
|
public abstract String convertMapTo(final Object... values);
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ package org.redkale.convert;
|
|||||||
import org.redkale.util.Attribute;
|
import org.redkale.util.Attribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 序列化的数据输出流
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -37,7 +38,7 @@ public abstract class Writer {
|
|||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public abstract boolean needWriteClassName();
|
public abstract boolean needWriteClassName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写入类名
|
* 写入类名
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import static org.redkale.convert.Reader.SIGN_NULL;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 以ByteBuffer为数据载体的BsonReader
|
||||||
|
*
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
@@ -24,7 +25,10 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
|
|
||||||
private ByteBuffer currentBuffer;
|
private ByteBuffer currentBuffer;
|
||||||
|
|
||||||
protected BsonByteBufferReader(ByteBuffer... buffers) {
|
protected ConvertMask mask;
|
||||||
|
|
||||||
|
protected BsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) {
|
||||||
|
this.mask = mask;
|
||||||
this.buffers = buffers;
|
this.buffers = buffers;
|
||||||
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
|
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
|
||||||
}
|
}
|
||||||
@@ -35,12 +39,13 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
this.currentIndex = 0;
|
this.currentIndex = 0;
|
||||||
this.currentBuffer = null;
|
this.currentBuffer = null;
|
||||||
this.buffers = null;
|
this.buffers = null;
|
||||||
|
this.mask = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte currentByte() {
|
protected byte currentByte() {
|
||||||
return currentBuffer.get(currentBuffer.position());
|
return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,13 +71,13 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
public byte readByte() {
|
public byte readByte() {
|
||||||
if (this.currentBuffer.hasRemaining()) {
|
if (this.currentBuffer.hasRemaining()) {
|
||||||
this.position++;
|
this.position++;
|
||||||
return this.currentBuffer.get();
|
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
this.currentBuffer = this.buffers[++this.currentIndex];
|
this.currentBuffer = this.buffers[++this.currentIndex];
|
||||||
if (this.currentBuffer.hasRemaining()) {
|
if (this.currentBuffer.hasRemaining()) {
|
||||||
this.position++;
|
this.position++;
|
||||||
return this.currentBuffer.get();
|
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,7 +88,11 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
int remain = this.currentBuffer.remaining();
|
int remain = this.currentBuffer.remaining();
|
||||||
if (remain >= 2) {
|
if (remain >= 2) {
|
||||||
this.position += 2;
|
this.position += 2;
|
||||||
return this.currentBuffer.getChar();
|
if (mask == null) {
|
||||||
|
return this.currentBuffer.getChar();
|
||||||
|
} else {
|
||||||
|
return (char) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
|
return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
|
||||||
@@ -95,7 +104,11 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
int remain = this.currentBuffer.remaining();
|
int remain = this.currentBuffer.remaining();
|
||||||
if (remain >= 2) {
|
if (remain >= 2) {
|
||||||
this.position += 2;
|
this.position += 2;
|
||||||
return this.currentBuffer.getShort();
|
if (mask == null) {
|
||||||
|
return this.currentBuffer.getShort();
|
||||||
|
} else {
|
||||||
|
return (short) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
|
return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
|
||||||
@@ -107,7 +120,14 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
int remain = this.currentBuffer.remaining();
|
int remain = this.currentBuffer.remaining();
|
||||||
if (remain >= 4) {
|
if (remain >= 4) {
|
||||||
this.position += 4;
|
this.position += 4;
|
||||||
return this.currentBuffer.getInt();
|
if (mask == null) {
|
||||||
|
return this.currentBuffer.getInt();
|
||||||
|
} else {
|
||||||
|
return ((mask.unmask(this.currentBuffer.get()) & 0xff) << 24)
|
||||||
|
| ((mask.unmask(this.currentBuffer.get()) & 0xff) << 16)
|
||||||
|
| ((mask.unmask(this.currentBuffer.get()) & 0xff) << 8)
|
||||||
|
| (mask.unmask(this.currentBuffer.get()) & 0xff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff);
|
return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff);
|
||||||
@@ -119,17 +139,28 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
int remain = this.currentBuffer.remaining();
|
int remain = this.currentBuffer.remaining();
|
||||||
if (remain >= 8) {
|
if (remain >= 8) {
|
||||||
this.position += 8;
|
this.position += 8;
|
||||||
return this.currentBuffer.getLong();
|
if (mask == null) {
|
||||||
|
return this.currentBuffer.getLong();
|
||||||
|
} else {
|
||||||
|
return ((((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 56)
|
||||||
|
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 48)
|
||||||
|
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 40)
|
||||||
|
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 32)
|
||||||
|
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 24)
|
||||||
|
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 16)
|
||||||
|
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 8)
|
||||||
|
| (((long) mask.unmask(this.currentBuffer.get()) & 0xff)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ((((long) readByte() & 0xff) << 56)
|
return ((((long) readByte() & 0xff) << 56)
|
||||||
| (((long) readByte() & 0xff) << 48)
|
| (((long) readByte() & 0xff) << 48)
|
||||||
| (((long) readByte() & 0xff) << 40)
|
| (((long) readByte() & 0xff) << 40)
|
||||||
| (((long) readByte() & 0xff) << 32)
|
| (((long) readByte() & 0xff) << 32)
|
||||||
| (((long) readByte() & 0xff) << 24)
|
| (((long) readByte() & 0xff) << 24)
|
||||||
| (((long) readByte() & 0xff) << 16)
|
| (((long) readByte() & 0xff) << 16)
|
||||||
| (((long) readByte() & 0xff) << 8)
|
| (((long) readByte() & 0xff) << 8)
|
||||||
| (((long) readByte() & 0xff)));
|
| (((long) readByte() & 0xff)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte[] read(final int len) {
|
protected byte[] read(final int len) {
|
||||||
@@ -149,9 +180,19 @@ public class BsonByteBufferReader extends BsonReader {
|
|||||||
if (remain >= len) {
|
if (remain >= len) {
|
||||||
this.position += len;
|
this.position += len;
|
||||||
this.currentBuffer.get(bs, pos, len);
|
this.currentBuffer.get(bs, pos, len);
|
||||||
|
if (mask != null) {
|
||||||
|
for (int i = pos, end = pos + len; i < end; i++) {
|
||||||
|
bs[i] = mask.unmask(bs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.currentBuffer.get(bs, pos, remain);
|
this.currentBuffer.get(bs, pos, remain);
|
||||||
|
if (mask != null) {
|
||||||
|
for (int i = pos, end = pos + remain; i < end; i++) {
|
||||||
|
bs[i] = mask.unmask(bs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.position += remain;
|
this.position += remain;
|
||||||
this.currentBuffer = this.buffers[++this.currentIndex];
|
this.currentBuffer = this.buffers[++this.currentIndex];
|
||||||
read(bs, pos + remain);
|
read(bs, pos + remain);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.util.function.*;
|
|||||||
import org.redkale.util.Utility;
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 以ByteBuffer为数据载体的BsonWriter
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -15,21 +15,21 @@ import org.redkale.util.*;
|
|||||||
/**
|
/**
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* BSON协议格式:
|
* BSON协议格式:
|
||||||
* 1). 基本数据类型: 直接转换成byte[]
|
* 1) 基本数据类型: 直接转换成byte[]
|
||||||
* 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
|
* 2) SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
|
||||||
* 3). String: length(4 bytes) + byte[](utf8);
|
* 3) String: length(4 bytes) + byte[](utf8);
|
||||||
* 4). 数组: length(4 bytes) + byte[]...
|
* 4) 数组: length(4 bytes) + byte[]...
|
||||||
* 5). Object:
|
* 5) Object:
|
||||||
* 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
|
* 1、 realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
|
||||||
* 2. 空字符串(SmallString)
|
* 2、 空字符串(SmallString)
|
||||||
* 3. SIGN_OBJECTB 标记位,值固定为0xBB (short)
|
* 3、 SIGN_OBJECTB 标记位,值固定为0xBB (short)
|
||||||
* 4. 循环字段值:
|
* 4、 循环字段值:
|
||||||
* 4.1 SIGN_HASNEXT 标记位,值固定为1 (byte)
|
* 4.1 SIGN_HASNEXT 标记位,值固定为1 (byte)
|
||||||
* 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object
|
* 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object
|
||||||
* 4.3 字段名 (SmallString)
|
* 4.3 字段名 (SmallString)
|
||||||
* 4.4 字段的值Object
|
* 4.4 字段的值Object
|
||||||
* 5. SIGN_NONEXT 标记位,值固定为0 (byte)
|
* 5、 SIGN_NONEXT 标记位,值固定为0 (byte)
|
||||||
* 6. SIGN_OBJECTE 标记位,值固定为0xEE (short)
|
* 6、 SIGN_OBJECTE 标记位,值固定为0xEE (short)
|
||||||
*
|
*
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
* <p>
|
* <p>
|
||||||
@@ -37,7 +37,7 @@ import org.redkale.util.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||||
|
|
||||||
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
||||||
return new BsonByteBufferReader(buffers);
|
return new BsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonReader pollBsonReader(final InputStream in) {
|
public BsonReader pollBsonReader(final InputStream in) {
|
||||||
@@ -99,6 +99,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
return convertFrom(type, bytes, 0, bytes.length);
|
return convertFrom(type, bytes, 0, bytes.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T convertFrom(final Type type, final byte[] bytes, final int start, final int len) {
|
public <T> T convertFrom(final Type type, final byte[] bytes, final int start, final int len) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
final BsonReader in = readerPool.get();
|
final BsonReader in = readerPool.get();
|
||||||
@@ -109,16 +110,27 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T convertFrom(final Type type, final InputStream in) {
|
public <T> T convertFrom(final Type type, final InputStream in) {
|
||||||
if (type == null || in == null) return null;
|
if (type == null || in == null) return null;
|
||||||
return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in));
|
return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
|
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
|
||||||
if (type == null || buffers.length < 1) return null;
|
if (type == null || buffers.length < 1) return null;
|
||||||
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(buffers));
|
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader((ConvertMask) null, buffers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) {
|
||||||
|
if (type == null || buffers.length < 1) return null;
|
||||||
|
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(mask, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T convertFrom(final Type type, final BsonReader reader) {
|
public <T> T convertFrom(final Type type, final BsonReader reader) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -127,6 +139,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertTo -----------------------------------------------------------
|
//------------------------------ convertTo -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
public byte[] convertTo(final Object value) {
|
public byte[] convertTo(final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
final BsonWriter out = writerPool.get().tiny(tiny);
|
final BsonWriter out = writerPool.get().tiny(tiny);
|
||||||
@@ -138,6 +151,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
return convertTo(value.getClass(), value);
|
return convertTo(value.getClass(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public byte[] convertTo(final Type type, final Object value) {
|
public byte[] convertTo(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
final BsonWriter out = writerPool.get().tiny(tiny);
|
final BsonWriter out = writerPool.get().tiny(tiny);
|
||||||
@@ -147,6 +161,16 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] convertMapTo(final Object... values) {
|
||||||
|
if (values == null) return null;
|
||||||
|
final BsonWriter out = writerPool.get().tiny(tiny);
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
|
||||||
|
byte[] result = out.toArray();
|
||||||
|
writerPool.offer(out);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
new BsonStreamWriter(tiny, out).writeNull();
|
||||||
@@ -164,6 +188,27 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
|
if (values == null) {
|
||||||
|
new BsonStreamWriter(tiny, out).writeNull();
|
||||||
|
} else {
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(new BsonStreamWriter(tiny, out), values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
|
if (supplier == null) return null;
|
||||||
|
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
factory.loadEncoder(value.getClass()).convertTo(out, value);
|
||||||
|
}
|
||||||
|
return out.toBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
||||||
@@ -175,13 +220,14 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
return out.toBuffers();
|
return out.toBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
@Override
|
||||||
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
||||||
if (value == null) {
|
if (values == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
factory.loadEncoder(value.getClass()).convertTo(out, value);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
|
||||||
}
|
}
|
||||||
return out.toBuffers();
|
return out.toBuffers();
|
||||||
}
|
}
|
||||||
@@ -199,6 +245,14 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void convertMapTo(final BsonWriter writer, final Object... values) {
|
||||||
|
if (values == null) {
|
||||||
|
writer.writeNull();
|
||||||
|
} else {
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BsonWriter convertToWriter(final Object value) {
|
public BsonWriter convertToWriter(final Object value) {
|
||||||
if (value == null) return null;
|
if (value == null) return null;
|
||||||
return convertToWriter(value.getClass(), value);
|
return convertToWriter(value.getClass(), value);
|
||||||
@@ -211,4 +265,9 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BsonWriter convertMapToWriter(final Object... values) {
|
||||||
|
final BsonWriter out = writerPool.get().tiny(tiny);
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ package org.redkale.convert.bson;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* BSON的ConvertFactory
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -27,6 +29,9 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
|||||||
static {
|
static {
|
||||||
instance.register(Serializable.class, objectDecoder);
|
instance.register(Serializable.class, objectDecoder);
|
||||||
instance.register(Serializable.class, objectEncoder);
|
instance.register(Serializable.class, objectEncoder);
|
||||||
|
|
||||||
|
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
|
||||||
|
instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BsonFactory(BsonFactory parent, boolean tiny) {
|
private BsonFactory(BsonFactory parent, boolean tiny) {
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.bson;
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
import java.util.function.*;
|
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import static org.redkale.convert.Reader.SIGN_NULL;
|
import static org.redkale.convert.Reader.SIGN_NULL;
|
||||||
import org.redkale.convert.ext.*;
|
import org.redkale.convert.ext.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* BSON数据源
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -42,19 +42,7 @@ public class BsonReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectPool<BsonReader> createPool(int max) {
|
public static ObjectPool<BsonReader> createPool(int max) {
|
||||||
return new ObjectPool<BsonReader>(max, new Creator<BsonReader>() {
|
return new ObjectPool<>(max, (Object... params) -> new BsonReader(), null, (t) -> t.recycle());
|
||||||
|
|
||||||
@Override
|
|
||||||
public BsonReader create(Object... params) {
|
|
||||||
return new BsonReader();
|
|
||||||
}
|
|
||||||
}, null, new Predicate<BsonReader>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(BsonReader t) {
|
|
||||||
return t.recycle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonReader(byte[] bytes) {
|
public BsonReader(byte[] bytes) {
|
||||||
@@ -99,6 +87,7 @@ public class BsonReader extends Reader {
|
|||||||
* 跳过属性的值
|
* 跳过属性的值
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public final void skipValue() {
|
public final void skipValue() {
|
||||||
if (typeval == 0) return;
|
if (typeval == 0) return;
|
||||||
final byte val = this.typeval;
|
final byte val = this.typeval;
|
||||||
@@ -164,7 +153,7 @@ public class BsonReader extends Reader {
|
|||||||
if (bt == Reader.SIGN_NULL) return null;
|
if (bt == Reader.SIGN_NULL) return null;
|
||||||
if (bt != SIGN_OBJECTB) {
|
if (bt != SIGN_OBJECTB) {
|
||||||
throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB)
|
throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB)
|
||||||
+ " (position = " + position + ") but '" + currentByte() + "'");
|
+ " (position = " + position + ") but '" + currentByte() + "'");
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -173,7 +162,7 @@ public class BsonReader extends Reader {
|
|||||||
public final void readObjectE(final Class clazz) {
|
public final void readObjectE(final Class clazz) {
|
||||||
if (readShort() != SIGN_OBJECTE) {
|
if (readShort() != SIGN_OBJECTE) {
|
||||||
throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE)
|
throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE)
|
||||||
+ " (position = " + position + ") but '" + currentByte() + "'");
|
+ " (position = " + position + ") but '" + currentByte() + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +212,7 @@ public class BsonReader extends Reader {
|
|||||||
byte b = readByte();
|
byte b = readByte();
|
||||||
if (b == SIGN_HASNEXT) return true;
|
if (b == SIGN_HASNEXT) return true;
|
||||||
if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT)
|
if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT)
|
||||||
+ " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")");
|
+ " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,19 +261,19 @@ public class BsonReader extends Reader {
|
|||||||
@Override
|
@Override
|
||||||
public int readInt() {
|
public int readInt() {
|
||||||
return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16)
|
return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16)
|
||||||
| ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
| ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long readLong() {
|
public long readLong() {
|
||||||
return ((((long) content[++this.position] & 0xff) << 56)
|
return ((((long) content[++this.position] & 0xff) << 56)
|
||||||
| (((long) content[++this.position] & 0xff) << 48)
|
| (((long) content[++this.position] & 0xff) << 48)
|
||||||
| (((long) content[++this.position] & 0xff) << 40)
|
| (((long) content[++this.position] & 0xff) << 40)
|
||||||
| (((long) content[++this.position] & 0xff) << 32)
|
| (((long) content[++this.position] & 0xff) << 32)
|
||||||
| (((long) content[++this.position] & 0xff) << 24)
|
| (((long) content[++this.position] & 0xff) << 24)
|
||||||
| (((long) content[++this.position] & 0xff) << 16)
|
| (((long) content[++this.position] & 0xff) << 16)
|
||||||
| (((long) content[++this.position] & 0xff) << 8)
|
| (((long) content[++this.position] & 0xff) << 8)
|
||||||
| (((long) content[++this.position] & 0xff)));
|
| (((long) content[++this.position] & 0xff)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.io.*;
|
|||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
@@ -21,6 +21,7 @@ class BsonStreamReader extends BsonByteBufferReader {
|
|||||||
private byte currByte;
|
private byte currByte;
|
||||||
|
|
||||||
protected BsonStreamReader(InputStream in) {
|
protected BsonStreamReader(InputStream in) {
|
||||||
|
super((ConvertMask) null);
|
||||||
this.in = in;
|
this.in = in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
package org.redkale.convert.bson;
|
package org.redkale.convert.bson;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
@@ -28,19 +27,7 @@ public class BsonWriter extends Writer {
|
|||||||
protected boolean tiny;
|
protected boolean tiny;
|
||||||
|
|
||||||
public static ObjectPool<BsonWriter> createPool(int max) {
|
public static ObjectPool<BsonWriter> createPool(int max) {
|
||||||
return new ObjectPool<BsonWriter>(max, new Creator<BsonWriter>() {
|
return new ObjectPool<>(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());
|
||||||
|
|
||||||
@Override
|
|
||||||
public BsonWriter create(Object... params) {
|
|
||||||
return new BsonWriter();
|
|
||||||
}
|
|
||||||
}, null, new Predicate<BsonWriter>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(BsonWriter t) {
|
|
||||||
return t.recycle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toArray() {
|
public byte[] toArray() {
|
||||||
@@ -82,6 +69,7 @@ public class BsonWriter extends Writer {
|
|||||||
* 扩充指定长度的缓冲区
|
* 扩充指定长度的缓冲区
|
||||||
*
|
*
|
||||||
* @param len 扩容长度
|
* @param len 扩容长度
|
||||||
|
*
|
||||||
* @return 固定0
|
* @return 固定0
|
||||||
*/
|
*/
|
||||||
protected int expand(int len) {
|
protected int expand(int len) {
|
||||||
@@ -248,11 +236,11 @@ public class BsonWriter extends Writer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char[] chars = Utility.charArray(value);
|
char[] chars = Utility.charArray(value);
|
||||||
if (chars.length > 255) throw new ConvertException("'" + value + "' has very long length");
|
if (chars.length > 255) throw new ConvertException("'" + value + "' have very long length");
|
||||||
byte[] bytes = new byte[chars.length + 1];
|
byte[] bytes = new byte[chars.length + 1];
|
||||||
bytes[0] = (byte) chars.length;
|
bytes[0] = (byte) chars.length;
|
||||||
for (int i = 0; i < chars.length; i++) {
|
for (int i = 0; i < chars.length; i++) {
|
||||||
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' has double-word");
|
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' have double-word");
|
||||||
bytes[i + 1] = (byte) chars[i];
|
bytes[i + 1] = (byte) chars[i];
|
||||||
}
|
}
|
||||||
writeTo(bytes);
|
writeTo(bytes);
|
||||||
|
|||||||
35
src/org/redkale/convert/ext/AtomicLongSimpledCoder.java
Normal file
35
src/org/redkale/convert/ext/AtomicLongSimpledCoder.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 java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AtomicLong 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public final class AtomicLongSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, AtomicLong> {
|
||||||
|
|
||||||
|
public static final AtomicLongSimpledCoder instance = new AtomicLongSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, AtomicLong value) {
|
||||||
|
out.writeLong(value == null ? 0 : value.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AtomicLong convertFrom(R in) {
|
||||||
|
return new AtomicLong(in.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
44
src/org/redkale/convert/ext/BigDecimalSimpledCoder.java
Normal file
44
src/org/redkale/convert/ext/BigDecimalSimpledCoder.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import org.redkale.convert.SimpledCoder;
|
||||||
|
import org.redkale.convert.Writer;
|
||||||
|
import org.redkale.convert.Reader;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BigDecimal 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public final class BigDecimalSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, BigDecimal> {
|
||||||
|
|
||||||
|
public static final BigDecimalSimpledCoder instance = new BigDecimalSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, BigDecimal value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.writeSmallString(value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal convertFrom(R in) {
|
||||||
|
String value = in.readSmallString();
|
||||||
|
if (value == null) return null;
|
||||||
|
return new BigDecimal(Utility.charArray(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
70
src/org/redkale/convert/ext/ByteBufferSimpledCoder.java
Normal file
70
src/org/redkale/convert/ext/ByteBufferSimpledCoder.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import org.redkale.convert.Reader;
|
||||||
|
import org.redkale.convert.SimpledCoder;
|
||||||
|
import org.redkale.convert.Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ByteBuffer 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public final class ByteBufferSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, ByteBuffer> {
|
||||||
|
|
||||||
|
public static final ByteBufferSimpledCoder instance = new ByteBufferSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, ByteBuffer value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.writeArrayB(value.remaining());
|
||||||
|
boolean flag = false;
|
||||||
|
for (byte v : value.array()) {
|
||||||
|
if (flag) out.writeArrayMark();
|
||||||
|
out.writeByte(v);
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
out.writeArrayE();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer convertFrom(R in) {
|
||||||
|
int len = in.readArrayB();
|
||||||
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
|
int size = 0;
|
||||||
|
byte[] data = new byte[8];
|
||||||
|
while (in.hasNext()) {
|
||||||
|
if (size >= data.length) {
|
||||||
|
byte[] newdata = new byte[data.length + 4];
|
||||||
|
System.arraycopy(data, 0, newdata, 0, size);
|
||||||
|
data = newdata;
|
||||||
|
}
|
||||||
|
data[size++] = in.readByte();
|
||||||
|
}
|
||||||
|
in.readArrayE();
|
||||||
|
return ByteBuffer.wrap(data, 0, size);
|
||||||
|
} else {
|
||||||
|
byte[] values = new byte[len];
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
values[i] = in.readByte();
|
||||||
|
}
|
||||||
|
in.readArrayE();
|
||||||
|
return ByteBuffer.wrap(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ public final class DateSimpledCoder<R extends Reader, W extends Writer> extends
|
|||||||
@Override
|
@Override
|
||||||
public Date convertFrom(R in) {
|
public Date convertFrom(R in) {
|
||||||
long t = in.readLong();
|
long t = in.readLong();
|
||||||
return t == 0 ? null : new Date();
|
return t == 0 ? null : new Date(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.ext;
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import java.util.stream.DoubleStream;
|
||||||
import org.redkale.convert.Reader;
|
import org.redkale.convert.Reader;
|
||||||
import org.redkale.convert.SimpledCoder;
|
import org.redkale.convert.SimpledCoder;
|
||||||
import org.redkale.convert.Writer;
|
import org.redkale.convert.Writer;
|
||||||
@@ -12,7 +13,9 @@ import org.redkale.convert.Writer;
|
|||||||
/**
|
/**
|
||||||
* double[] 的SimpledCoder实现
|
* double[] 的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输出的子类型
|
||||||
@@ -66,4 +69,24 @@ public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final static class DoubleStreamSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, DoubleStream> {
|
||||||
|
|
||||||
|
public static final DoubleStreamSimpledCoder instance = new DoubleStreamSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, DoubleStream values) {
|
||||||
|
if (values == null) {
|
||||||
|
out.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DoubleArraySimpledCoder.instance.convertTo(out, values.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleStream convertFrom(R in) {
|
||||||
|
double[] value = DoubleArraySimpledCoder.instance.convertFrom(in);
|
||||||
|
return value == null ? null : DoubleStream.of(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/org/redkale/convert/ext/FileSimpledCoder.java
Normal file
41
src/org/redkale/convert/ext/FileSimpledCoder.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.io.File;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件 的SimpledCoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
* @param <W> Writer输出的子类型
|
||||||
|
*/
|
||||||
|
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
||||||
|
|
||||||
|
public static final PatternSimpledCoder instance = new PatternSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, File value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
out.writeString(value.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File convertFrom(R in) {
|
||||||
|
String value = in.readString();
|
||||||
|
if (value == null) return null;
|
||||||
|
return new File(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import java.net.*;
|
|||||||
* @param <R> Reader输入的子类型
|
* @param <R> Reader输入的子类型
|
||||||
* @param <W> Writer输出的子类型
|
* @param <W> Writer输出的子类型
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetAddress> {
|
public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetAddress> {
|
||||||
|
|
||||||
public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder();
|
public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder();
|
||||||
@@ -50,6 +51,7 @@ public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> e
|
|||||||
* @param <R> Reader输入的子类型
|
* @param <R> Reader输入的子类型
|
||||||
* @param <W> Writer输出的子类型
|
* @param <W> Writer输出的子类型
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public final static class InetSocketAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetSocketAddress> {
|
public final static class InetSocketAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetSocketAddress> {
|
||||||
|
|
||||||
public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder();
|
public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.ext;
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import java.util.stream.IntStream;
|
||||||
import org.redkale.convert.Reader;
|
import org.redkale.convert.Reader;
|
||||||
import org.redkale.convert.SimpledCoder;
|
import org.redkale.convert.SimpledCoder;
|
||||||
import org.redkale.convert.Writer;
|
import org.redkale.convert.Writer;
|
||||||
@@ -12,7 +13,9 @@ import org.redkale.convert.Writer;
|
|||||||
/**
|
/**
|
||||||
* int[] 的SimpledCoder实现
|
* int[] 的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输出的子类型
|
||||||
@@ -66,4 +69,24 @@ public final class IntArraySimpledCoder<R extends Reader, W extends Writer> exte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final static class IntStreamSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, IntStream> {
|
||||||
|
|
||||||
|
public static final IntStreamSimpledCoder instance = new IntStreamSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, IntStream values) {
|
||||||
|
if (values == null) {
|
||||||
|
out.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IntArraySimpledCoder.instance.convertTo(out, values.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntStream convertFrom(R in) {
|
||||||
|
int[] value = IntArraySimpledCoder.instance.convertFrom(in);
|
||||||
|
return value == null ? null : IntStream.of(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.convert.ext;
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
|
import java.util.stream.LongStream;
|
||||||
import org.redkale.convert.Reader;
|
import org.redkale.convert.Reader;
|
||||||
import org.redkale.convert.SimpledCoder;
|
import org.redkale.convert.SimpledCoder;
|
||||||
import org.redkale.convert.Writer;
|
import org.redkale.convert.Writer;
|
||||||
@@ -68,4 +69,24 @@ public final class LongArraySimpledCoder<R extends Reader, W extends Writer> ext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final static class LongStreamSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, LongStream> {
|
||||||
|
|
||||||
|
public static final LongStreamSimpledCoder instance = new LongStreamSimpledCoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, LongStream values) {
|
||||||
|
if (values == null) {
|
||||||
|
out.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LongArraySimpledCoder.instance.convertTo(out, values.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongStream convertFrom(R in) {
|
||||||
|
long[] value = LongArraySimpledCoder.instance.convertFrom(in);
|
||||||
|
return value == null ? null : LongStream.of(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ public class TypeSimpledCoder<R extends Reader, W extends Writer> extends Simple
|
|||||||
String str = in.readSmallString();
|
String str = in.readSmallString();
|
||||||
if (str == null) return null;
|
if (str == null) return null;
|
||||||
try {
|
try {
|
||||||
return Class.forName(str);
|
return Thread.currentThread().getContextClassLoader().loadClass(str);
|
||||||
} catch (Exception e) {
|
} catch (Throwable e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import org.redkale.convert.*;
|
|||||||
import static org.redkale.convert.Reader.*;
|
import static org.redkale.convert.Reader.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 以ByteBuffer为数据载体的JsonReader <br>
|
||||||
|
*
|
||||||
* 只支持UTF-8格式
|
* 只支持UTF-8格式
|
||||||
*
|
*
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
@@ -28,7 +29,10 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
|
|
||||||
private ByteBuffer currentBuffer;
|
private ByteBuffer currentBuffer;
|
||||||
|
|
||||||
protected JsonByteBufferReader(ByteBuffer... buffers) {
|
protected ConvertMask mask;
|
||||||
|
|
||||||
|
protected JsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) {
|
||||||
|
this.mask = mask;
|
||||||
this.buffers = buffers;
|
this.buffers = buffers;
|
||||||
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
|
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
|
||||||
}
|
}
|
||||||
@@ -40,19 +44,20 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
this.currentChar = 0;
|
this.currentChar = 0;
|
||||||
this.currentBuffer = null;
|
this.currentBuffer = null;
|
||||||
this.buffers = null;
|
this.buffers = null;
|
||||||
|
this.mask = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte nextByte() {
|
protected byte nextByte() {
|
||||||
if (this.currentBuffer.hasRemaining()) {
|
if (this.currentBuffer.hasRemaining()) {
|
||||||
this.position++;
|
this.position++;
|
||||||
return this.currentBuffer.get();
|
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
this.currentBuffer = this.buffers[++this.currentIndex];
|
this.currentBuffer = this.buffers[++this.currentIndex];
|
||||||
if (this.currentBuffer.hasRemaining()) {
|
if (this.currentBuffer.hasRemaining()) {
|
||||||
this.position++;
|
this.position++;
|
||||||
return this.currentBuffer.get();
|
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +162,7 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
public final boolean hasNext() {
|
public final boolean hasNext() {
|
||||||
char ch = nextGoodChar();
|
char ch = nextGoodChar();
|
||||||
if (ch == ',') return true;
|
if (ch == ',') return true;
|
||||||
if (ch == '}' || ch == ']') return false;
|
if (ch == '}' || ch == ']' || ch == 0) return false;
|
||||||
backChar(ch); // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
|
backChar(ch); // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -248,6 +253,7 @@ public class JsonByteBufferReader extends JsonReader {
|
|||||||
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")");
|
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")");
|
||||||
}
|
}
|
||||||
} else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 包含 0
|
} else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 包含 0
|
||||||
|
backChar(ch);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
sb.append(ch);
|
sb.append(ch);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.redkale.convert.*;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 以ByteBuffer为数据载体的JsonWriter
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.redkale.util.*;
|
|||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||||
|
|
||||||
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.LinkedHashMap<String, String>>() {
|
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.LinkedHashMap<String, String>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
@@ -48,7 +48,7 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
||||||
return new JsonByteBufferReader(buffers);
|
return new JsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonReader pollJsonReader(final InputStream in) {
|
public JsonReader pollJsonReader(final InputStream in) {
|
||||||
@@ -109,9 +109,16 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
return (T) factory.loadDecoder(type).convertFrom(new JsonStreamReader(in));
|
return (T) factory.loadDecoder(type).convertFrom(new JsonStreamReader(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
|
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
|
||||||
if (type == null || buffers == null || buffers.length == 0) return null;
|
if (type == null || buffers == null || buffers.length == 0) return null;
|
||||||
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader(buffers));
|
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) {
|
||||||
|
if (type == null || buffers == null || buffers.length == 0) return null;
|
||||||
|
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader(mask, buffers));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T convertFrom(final Type type, final JsonReader reader) {
|
public <T> T convertFrom(final Type type, final JsonReader reader) {
|
||||||
@@ -122,11 +129,13 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertTo -----------------------------------------------------------
|
//------------------------------ convertTo -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
public String convertTo(final Object value) {
|
public String convertTo(final Object value) {
|
||||||
if (value == null) return "null";
|
if (value == null) return "null";
|
||||||
return convertTo(value.getClass(), value);
|
return convertTo(value.getClass(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String convertTo(final Type type, final Object value) {
|
public String convertTo(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
if (value == null) return "null";
|
if (value == null) return "null";
|
||||||
@@ -137,6 +146,16 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertMapTo(final Object... values) {
|
||||||
|
if (values == null) return "null";
|
||||||
|
final JsonWriter out = writerPool.get().tiny(tiny);
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
|
||||||
|
String result = out.toString();
|
||||||
|
writerPool.offer(out);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
new JsonStreamWriter(tiny, out).writeNull();
|
||||||
@@ -154,6 +173,15 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
|
if (values == null) {
|
||||||
|
new JsonStreamWriter(tiny, out).writeNull();
|
||||||
|
} else {
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(new JsonStreamWriter(tiny, out), values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
||||||
@@ -165,6 +193,7 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
return out.toBuffers();
|
return out.toBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
||||||
@@ -176,6 +205,18 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
return out.toBuffers();
|
return out.toBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
|
if (supplier == null) return null;
|
||||||
|
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
||||||
|
if (values == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
|
||||||
|
}
|
||||||
|
return out.toBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
public void convertTo(final JsonWriter writer, final Object value) {
|
public void convertTo(final JsonWriter writer, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
writer.writeNull();
|
writer.writeNull();
|
||||||
@@ -193,6 +234,14 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void convertMapTo(final JsonWriter writer, final Object... values) {
|
||||||
|
if (values == null) {
|
||||||
|
writer.writeNull();
|
||||||
|
} else {
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public JsonWriter convertToWriter(final Object value) {
|
public JsonWriter convertToWriter(final Object value) {
|
||||||
if (value == null) return null;
|
if (value == null) return null;
|
||||||
return convertToWriter(value.getClass(), value);
|
return convertToWriter(value.getClass(), value);
|
||||||
@@ -204,4 +253,10 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
|
|||||||
factory.loadEncoder(type).convertTo(out, value);
|
factory.loadEncoder(type).convertTo(out, value);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JsonWriter convertMapToWriter(final Object... values) {
|
||||||
|
final JsonWriter out = writerPool.get().tiny(tiny);
|
||||||
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,15 +10,17 @@ import java.math.BigInteger;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
import org.redkale.convert.ext.*;
|
import org.redkale.convert.ext.*;
|
||||||
import org.redkale.util.DLong;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* JSON的ConvertFactory
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||||
|
|
||||||
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
|
private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny"));
|
||||||
@@ -29,6 +31,9 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
|||||||
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
|
||||||
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
|
||||||
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
||||||
|
|
||||||
|
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
|
||||||
|
instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonFactory(JsonFactory parent, boolean tiny) {
|
private JsonFactory(JsonFactory parent, boolean tiny) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import static org.redkale.convert.Reader.*;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* JSON数据源
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -161,6 +162,7 @@ public class JsonReader extends Reader {
|
|||||||
* 判断下一个非空白字符是否为{
|
* 判断下一个非空白字符是否为{
|
||||||
*
|
*
|
||||||
* @param clazz 类名
|
* @param clazz 类名
|
||||||
|
*
|
||||||
* @return 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
* @return 返回 null 表示对象为null, 返回空字符串表示当前class与返回的class一致,返回非空字符串表示class是当前class的子类。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -403,6 +405,7 @@ public class JsonReader extends Reader {
|
|||||||
@Override
|
@Override
|
||||||
public final DeMember readFieldName(final DeMember[] members) {
|
public final DeMember readFieldName(final DeMember[] members) {
|
||||||
final String exceptedfield = this.readSmallString();
|
final String exceptedfield = this.readSmallString();
|
||||||
|
if (exceptedfield == null) return null;
|
||||||
final int len = members.length;
|
final int len = members.length;
|
||||||
if (this.fieldIndex >= len) this.fieldIndex = 0;
|
if (this.fieldIndex >= len) this.fieldIndex = 0;
|
||||||
for (int k = this.fieldIndex; k < len; k++) {
|
for (int k = this.fieldIndex; k < len; k++) {
|
||||||
@@ -473,12 +476,22 @@ public class JsonReader extends Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expected != '"' && expected != '\'') {
|
if (expected != '"' && expected != '\'') {
|
||||||
if (expected == 'n' && text0.length > currpos + 3) {
|
if (expected == 'n' && text0.length > currpos + 3 && (text0[1 + currpos] == 'u' && text0[2 + currpos] == 'l' && text0[3 + currpos] == 'l')) {
|
||||||
if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') {
|
if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') {
|
||||||
this.position = currpos;
|
this.position = currpos;
|
||||||
if (text0.length > currpos + 4) {
|
if (text0.length > currpos + 4) {
|
||||||
char ch = text0[currpos + 1];
|
char ch = text0[currpos + 1];
|
||||||
if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') return null;
|
if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') return null;
|
||||||
|
final int start = currpos - 3;
|
||||||
|
for (;;) {
|
||||||
|
if (currpos >= text0.length) break;
|
||||||
|
ch = text0[currpos];
|
||||||
|
if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break;
|
||||||
|
currpos++;
|
||||||
|
}
|
||||||
|
if (currpos == start) throw new ConvertException("expected a string after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")");
|
||||||
|
this.position = currpos - 1;
|
||||||
|
return new String(text0, start, currpos - start);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -486,6 +499,7 @@ public class JsonReader extends Reader {
|
|||||||
} else {
|
} else {
|
||||||
final int start = currpos;
|
final int start = currpos;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
if (currpos >= text0.length) break;
|
||||||
char ch = text0[currpos];
|
char ch = text0[currpos];
|
||||||
if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break;
|
if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break;
|
||||||
currpos++;
|
currpos++;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import org.redkale.convert.*;
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
class JsonStreamReader extends JsonByteBufferReader {
|
class JsonStreamReader extends JsonByteBufferReader {
|
||||||
@@ -19,6 +19,7 @@ class JsonStreamReader extends JsonByteBufferReader {
|
|||||||
private InputStream in;
|
private InputStream in;
|
||||||
|
|
||||||
protected JsonStreamReader(InputStream in) {
|
protected JsonStreamReader(InputStream in) {
|
||||||
|
super((ConvertMask) null);
|
||||||
this.in = in;
|
this.in = in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -25,6 +26,24 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
protected Object subobject; //用于存储绑定在Connection上的对象, 同attributes, 只绑定单个对象时尽量使用subobject而非attributes
|
protected Object subobject; //用于存储绑定在Connection上的对象, 同attributes, 只绑定单个对象时尽量使用subobject而非attributes
|
||||||
|
|
||||||
|
protected volatile long readtime;
|
||||||
|
|
||||||
|
protected volatile long writetime;
|
||||||
|
|
||||||
|
//关闭数
|
||||||
|
AtomicLong closedCounter;
|
||||||
|
|
||||||
|
//在线数
|
||||||
|
AtomicLong livingCounter;
|
||||||
|
|
||||||
|
public final long getLastReadTime() {
|
||||||
|
return readtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final long getLastWriteTime() {
|
||||||
|
return writetime;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract boolean isTCP();
|
public abstract boolean isTCP();
|
||||||
|
|
||||||
public abstract SocketAddress getRemoteAddress();
|
public abstract SocketAddress getRemoteAddress();
|
||||||
@@ -43,7 +62,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
write(srcs, 0, srcs.length, attachment, handler);
|
write(srcs, 0, srcs.length, attachment, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
||||||
|
|
||||||
public void dispose() {//同close, 只是去掉throws IOException
|
public void dispose() {//同close, 只是去掉throws IOException
|
||||||
try {
|
try {
|
||||||
@@ -54,6 +73,14 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
|
if (closedCounter != null) {
|
||||||
|
closedCounter.incrementAndGet();
|
||||||
|
closedCounter = null;
|
||||||
|
}
|
||||||
|
if (livingCounter != null) {
|
||||||
|
livingCounter.decrementAndGet();
|
||||||
|
livingCounter = null;
|
||||||
|
}
|
||||||
if (attributes == null) return;
|
if (attributes == null) return;
|
||||||
try {
|
try {
|
||||||
for (Object obj : attributes.values()) {
|
for (Object obj : attributes.values()) {
|
||||||
@@ -95,39 +122,58 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
public static AsyncConnection create(final String protocol, final AsynchronousChannelGroup group, final SocketAddress address) throws IOException {
|
/**
|
||||||
return create(protocol, group, address, 0, 0);
|
* 创建TCP协议客户端连接
|
||||||
|
*
|
||||||
|
* @param address 连接点子
|
||||||
|
* @param group 连接AsynchronousChannelGroup
|
||||||
|
* @param readTimeoutSecond 读取超时秒数
|
||||||
|
* @param writeTimeoutSecond 写入超时秒数
|
||||||
|
*
|
||||||
|
* @return 连接CompletableFuture
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SocketAddress address,
|
||||||
|
final int readTimeoutSecond, final int writeTimeoutSecond) {
|
||||||
|
return createTCP(group, address, false, readTimeoutSecond, writeTimeoutSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建客户端连接
|
* 创建TCP协议客户端连接
|
||||||
*
|
*
|
||||||
* @param protocol 连接类型 只能是TCP或UDP
|
* @param address 连接点子
|
||||||
* @param address 连接点子
|
* @param group 连接AsynchronousChannelGroup
|
||||||
* @param group 连接AsynchronousChannelGroup
|
* @param noDelay TcpNoDelay
|
||||||
* @param readTimeoutSecond0 读取超时秒数
|
* @param readTimeoutSecond 读取超时秒数
|
||||||
* @param writeTimeoutSecond0 写入超时秒数
|
* @param writeTimeoutSecond 写入超时秒数
|
||||||
* @return 连接
|
*
|
||||||
* @throws java.io.IOException 异常
|
* @return 连接CompletableFuture
|
||||||
*/
|
*/
|
||||||
public static AsyncConnection create(final String protocol, final AsynchronousChannelGroup group, final SocketAddress address,
|
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SocketAddress address,
|
||||||
final int readTimeoutSecond0, final int writeTimeoutSecond0) throws IOException {
|
final boolean noDelay, final int readTimeoutSecond, final int writeTimeoutSecond) {
|
||||||
if ("TCP".equalsIgnoreCase(protocol)) {
|
final CompletableFuture future = new CompletableFuture();
|
||||||
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group);
|
try {
|
||||||
try {
|
final AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group);
|
||||||
channel.connect(address).get(3, TimeUnit.SECONDS);
|
channel.connect(address, null, new CompletionHandler<Void, Void>() {
|
||||||
} catch (Exception e) {
|
@Override
|
||||||
throw new IOException("AsyncConnection connect " + address, e);
|
public void completed(Void result, Void attachment) {
|
||||||
}
|
if (noDelay) {
|
||||||
return create(channel, address, readTimeoutSecond0, writeTimeoutSecond0);
|
try {
|
||||||
} else if ("UDP".equalsIgnoreCase(protocol)) {
|
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
||||||
DatagramChannel channel = DatagramChannel.open();
|
} catch (IOException e) {
|
||||||
channel.configureBlocking(true);
|
}
|
||||||
channel.connect(address);
|
}
|
||||||
return create(channel, address, true, readTimeoutSecond0, writeTimeoutSecond0);
|
future.complete(create(channel, address, readTimeoutSecond, writeTimeoutSecond));
|
||||||
} else {
|
}
|
||||||
throw new RuntimeException("AsyncConnection not support protocol " + protocol);
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable exc, Void attachment) {
|
||||||
|
future.completeExceptionally(exc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
future.completeExceptionally(e);
|
||||||
}
|
}
|
||||||
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BIOUDPAsyncConnection extends AsyncConnection {
|
private static class BIOUDPAsyncConnection extends AsyncConnection {
|
||||||
@@ -143,7 +189,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
private final boolean client;
|
private final boolean client;
|
||||||
|
|
||||||
public BIOUDPAsyncConnection(final DatagramChannel ch, SocketAddress addr,
|
public BIOUDPAsyncConnection(final DatagramChannel ch, SocketAddress addr,
|
||||||
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
||||||
this.channel = ch;
|
this.channel = ch;
|
||||||
this.client = client0;
|
this.client = client0;
|
||||||
this.readTimeoutSecond = readTimeoutSecond0;
|
this.readTimeoutSecond = readTimeoutSecond0;
|
||||||
@@ -186,13 +232,14 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
try {
|
try {
|
||||||
int rs = 0;
|
int rs = 0;
|
||||||
for (int i = offset; i < offset + length; i++) {
|
for (int i = offset; i < offset + length; i++) {
|
||||||
rs += channel.send(srcs[i], remoteAddress);
|
rs += channel.send(srcs[i], remoteAddress);
|
||||||
if (i != offset) Thread.sleep(10);
|
if (i != offset) Thread.sleep(10);
|
||||||
}
|
}
|
||||||
|
this.writetime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, attachment);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, attachment);
|
||||||
@@ -203,6 +250,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
try {
|
try {
|
||||||
int rs = channel.read(dst);
|
int rs = channel.read(dst);
|
||||||
|
this.readtime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, attachment);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, attachment);
|
||||||
@@ -213,7 +261,8 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public Future<Integer> read(ByteBuffer dst) {
|
public Future<Integer> read(ByteBuffer dst) {
|
||||||
try {
|
try {
|
||||||
int rs = channel.read(dst);
|
int rs = channel.read(dst);
|
||||||
return new SimpleFuture(rs);
|
this.readtime = System.currentTimeMillis();
|
||||||
|
return CompletableFuture.completedFuture(rs);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -223,6 +272,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
try {
|
try {
|
||||||
int rs = channel.send(src, remoteAddress);
|
int rs = channel.send(src, remoteAddress);
|
||||||
|
this.writetime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, attachment);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, attachment);
|
||||||
@@ -233,7 +283,8 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public Future<Integer> write(ByteBuffer src) {
|
public Future<Integer> write(ByteBuffer src) {
|
||||||
try {
|
try {
|
||||||
int rs = channel.send(src, remoteAddress);
|
int rs = channel.send(src, remoteAddress);
|
||||||
return new SimpleFuture(rs);
|
this.writetime = System.currentTimeMillis();
|
||||||
|
return CompletableFuture.completedFuture(rs);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -257,45 +308,10 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
|
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
|
||||||
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
||||||
return new BIOUDPAsyncConnection(ch, addr, client0, readTimeoutSecond0, writeTimeoutSecond0);
|
return new BIOUDPAsyncConnection(ch, addr, client0, readTimeoutSecond0, writeTimeoutSecond0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SimpleFuture implements Future<Integer> {
|
|
||||||
|
|
||||||
private final int rs;
|
|
||||||
|
|
||||||
public SimpleFuture(int rs) {
|
|
||||||
this.rs = rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDone() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer get() throws InterruptedException, ExecutionException {
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class BIOTCPAsyncConnection extends AsyncConnection {
|
private static class BIOTCPAsyncConnection extends AsyncConnection {
|
||||||
|
|
||||||
private int readTimeoutSecond;
|
private int readTimeoutSecond;
|
||||||
@@ -372,12 +388,13 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
try {
|
try {
|
||||||
int rs = 0;
|
int rs = 0;
|
||||||
for (int i = offset; i < offset + length; i++) {
|
for (int i = offset; i < offset + length; i++) {
|
||||||
rs += writeChannel.write(srcs[i]);
|
rs += writeChannel.write(srcs[i]);
|
||||||
}
|
}
|
||||||
|
this.writetime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, attachment);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, attachment);
|
||||||
@@ -388,6 +405,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
try {
|
try {
|
||||||
int rs = readChannel.read(dst);
|
int rs = readChannel.read(dst);
|
||||||
|
this.readtime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, attachment);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, attachment);
|
||||||
@@ -398,7 +416,8 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public Future<Integer> read(ByteBuffer dst) {
|
public Future<Integer> read(ByteBuffer dst) {
|
||||||
try {
|
try {
|
||||||
int rs = readChannel.read(dst);
|
int rs = readChannel.read(dst);
|
||||||
return new SimpleFuture(rs);
|
this.readtime = System.currentTimeMillis();
|
||||||
|
return CompletableFuture.completedFuture(rs);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -408,6 +427,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
try {
|
try {
|
||||||
int rs = writeChannel.write(src);
|
int rs = writeChannel.write(src);
|
||||||
|
this.writetime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, attachment);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, attachment);
|
||||||
@@ -418,7 +438,8 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public Future<Integer> write(ByteBuffer src) {
|
public Future<Integer> write(ByteBuffer src) {
|
||||||
try {
|
try {
|
||||||
int rs = writeChannel.write(src);
|
int rs = writeChannel.write(src);
|
||||||
return new SimpleFuture(rs);
|
this.writetime = System.currentTimeMillis();
|
||||||
|
return CompletableFuture.completedFuture(rs);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -440,6 +461,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
* 通常用于 ssl socket
|
* 通常用于 ssl socket
|
||||||
*
|
*
|
||||||
* @param socket Socket对象
|
* @param socket Socket对象
|
||||||
|
*
|
||||||
* @return 连接对象
|
* @return 连接对象
|
||||||
*/
|
*/
|
||||||
public static AsyncConnection create(final Socket socket) {
|
public static AsyncConnection create(final Socket socket) {
|
||||||
@@ -477,6 +499,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
|
this.readtime = System.currentTimeMillis();
|
||||||
if (readTimeoutSecond > 0) {
|
if (readTimeoutSecond > 0) {
|
||||||
channel.read(dst, readTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
|
channel.read(dst, readTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
|
||||||
} else {
|
} else {
|
||||||
@@ -486,6 +509,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
|
this.writetime = System.currentTimeMillis();
|
||||||
if (writeTimeoutSecond > 0) {
|
if (writeTimeoutSecond > 0) {
|
||||||
channel.write(src, writeTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
|
channel.write(src, writeTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
|
||||||
} else {
|
} else {
|
||||||
@@ -495,6 +519,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler<Integer, ? super A> handler) {
|
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler<Integer, ? super A> handler) {
|
||||||
|
this.writetime = System.currentTimeMillis();
|
||||||
channel.write(srcs, offset, length, writeTimeoutSecond > 0 ? writeTimeoutSecond : 60, TimeUnit.SECONDS,
|
channel.write(srcs, offset, length, writeTimeoutSecond > 0 ? writeTimeoutSecond : 60, TimeUnit.SECONDS,
|
||||||
attachment, new CompletionHandler<Long, A>() {
|
attachment, new CompletionHandler<Long, A>() {
|
||||||
|
|
||||||
@@ -577,8 +602,8 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
return create(ch, null, 0, 0);
|
return create(ch, null, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSecond, final int writeTimeoutSecond) {
|
||||||
return new AIOTCPAsyncConnection(ch, addr0, readTimeoutSecond0, writeTimeoutSecond0);
|
return new AIOTCPAsyncConnection(ch, addr0, readTimeoutSecond, writeTimeoutSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.net;
|
package org.redkale.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
|
import java.nio.channels.AsynchronousChannelGroup;
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
@@ -14,50 +16,63 @@ import java.util.logging.*;
|
|||||||
import org.redkale.convert.bson.*;
|
import org.redkale.convert.bson.*;
|
||||||
import org.redkale.convert.json.*;
|
import org.redkale.convert.json.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
import org.redkale.watch.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 服务器上下文对象
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class Context {
|
public class Context {
|
||||||
|
|
||||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||||
|
|
||||||
|
//服务启动时间
|
||||||
protected final long serverStartTime;
|
protected final long serverStartTime;
|
||||||
|
|
||||||
protected final ExecutorService executor;
|
//Server的线程池
|
||||||
|
protected final ThreadPoolExecutor executor;
|
||||||
|
|
||||||
|
//ByteBuffer的容量,默认8K
|
||||||
protected final int bufferCapacity;
|
protected final int bufferCapacity;
|
||||||
|
|
||||||
|
//ByteBuffer对象池
|
||||||
protected final ObjectPool<ByteBuffer> bufferPool;
|
protected final ObjectPool<ByteBuffer> bufferPool;
|
||||||
|
|
||||||
|
//Response对象池
|
||||||
protected final ObjectPool<Response> responsePool;
|
protected final ObjectPool<Response> responsePool;
|
||||||
|
|
||||||
|
//服务的根Servlet
|
||||||
protected final PrepareServlet prepare;
|
protected final PrepareServlet prepare;
|
||||||
|
|
||||||
|
//服务的监听地址
|
||||||
private final InetSocketAddress address;
|
private final InetSocketAddress address;
|
||||||
|
|
||||||
|
//字符集
|
||||||
protected final Charset charset;
|
protected final Charset charset;
|
||||||
|
|
||||||
|
//请求内容的大小上限, 默认64K
|
||||||
protected final int maxbody;
|
protected final int maxbody;
|
||||||
|
|
||||||
|
//IO读取的超时时间
|
||||||
protected final int readTimeoutSecond;
|
protected final int readTimeoutSecond;
|
||||||
|
|
||||||
|
//IO写入的超时时间
|
||||||
protected final int writeTimeoutSecond;
|
protected final int writeTimeoutSecond;
|
||||||
|
|
||||||
|
//日志Logger
|
||||||
protected final Logger logger;
|
protected final Logger logger;
|
||||||
|
|
||||||
|
//BSON操作工厂
|
||||||
protected final BsonFactory bsonFactory;
|
protected final BsonFactory bsonFactory;
|
||||||
|
|
||||||
|
//JSON操作工厂
|
||||||
protected final JsonFactory jsonFactory;
|
protected final JsonFactory jsonFactory;
|
||||||
|
|
||||||
protected final WatchFactory watch;
|
public Context(long serverStartTime, Logger logger, ThreadPoolExecutor executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,
|
||||||
|
final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final int readTimeoutSecond, final int writeTimeoutSecond) {
|
||||||
public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,
|
|
||||||
final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final WatchFactory watch,
|
|
||||||
final int readTimeoutSecond, final int writeTimeoutSecond) {
|
|
||||||
this.serverStartTime = serverStartTime;
|
this.serverStartTime = serverStartTime;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
@@ -68,7 +83,6 @@ public class Context {
|
|||||||
this.charset = UTF8.equals(charset) ? null : charset;
|
this.charset = UTF8.equals(charset) ? null : charset;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.prepare = prepare;
|
this.prepare = prepare;
|
||||||
this.watch = watch;
|
|
||||||
this.readTimeoutSecond = readTimeoutSecond;
|
this.readTimeoutSecond = readTimeoutSecond;
|
||||||
this.writeTimeoutSecond = writeTimeoutSecond;
|
this.writeTimeoutSecond = writeTimeoutSecond;
|
||||||
this.jsonFactory = JsonFactory.root();
|
this.jsonFactory = JsonFactory.root();
|
||||||
@@ -91,8 +105,16 @@ public class Context {
|
|||||||
return charset;
|
return charset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void submit(Runnable r) {
|
public Future<?> submitAsync(Runnable r) {
|
||||||
executor.submit(r);
|
return executor.submit(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsynchronousChannelGroup createAsynchronousChannelGroup() throws IOException {
|
||||||
|
return AsynchronousChannelGroup.withThreadPool(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runAsync(Runnable r) {
|
||||||
|
executor.execute(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBufferCapacity() {
|
public int getBufferCapacity() {
|
||||||
@@ -111,6 +133,13 @@ public class Context {
|
|||||||
bufferPool.offer(buffer);
|
bufferPool.offer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(ByteBuffer... buffers) {
|
||||||
|
if (buffers == null) return;
|
||||||
|
for (ByteBuffer buffer : buffers) {
|
||||||
|
bufferPool.offer(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Logger getLogger() {
|
public Logger getLogger() {
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/org/redkale/net/Filter.java
Normal file
44
src/org/redkale/net/Filter.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.annotation.Priority;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 协议拦截器类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <C> Context的子类型
|
||||||
|
* @param <R> Request的子类型
|
||||||
|
* @param <P> Response的子类型
|
||||||
|
*/
|
||||||
|
public abstract class Filter<C extends Context, R extends Request<C>, P extends Response<C, R>> implements Comparable {
|
||||||
|
|
||||||
|
AnyValue _conf; //当前Filter的配置
|
||||||
|
|
||||||
|
Filter<C, R, P> _next; //下一个Filter
|
||||||
|
|
||||||
|
public void init(C context, AnyValue config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void doFilter(R request, P response) throws IOException;
|
||||||
|
|
||||||
|
public void destroy(C context, AnyValue config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Object o) {
|
||||||
|
if (!(o instanceof Filter)) return 1;
|
||||||
|
Priority p1 = this.getClass().getAnnotation(Priority.class);
|
||||||
|
Priority p2 = o.getClass().getAnnotation(Priority.class);
|
||||||
|
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,11 @@ import java.util.logging.*;
|
|||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 根Servlet的处理逻辑类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
@@ -10,10 +10,14 @@ import java.nio.*;
|
|||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 根Servlet, 一个Server只能存在一个根Servlet
|
||||||
|
*
|
||||||
|
* 用于分发Request请求
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -31,10 +35,179 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
|
|
||||||
protected final AtomicLong illRequestCounter = new AtomicLong(); //错误请求次数
|
protected final AtomicLong illRequestCounter = new AtomicLong(); //错误请求次数
|
||||||
|
|
||||||
protected final Set<S> servlets = new HashSet<>();
|
private final Object lock1 = new Object();
|
||||||
|
|
||||||
protected final Map<K, S> mappings = new HashMap<>();
|
private Set<S> servlets = new HashSet<>();
|
||||||
|
|
||||||
|
private final Object lock2 = new Object();
|
||||||
|
|
||||||
|
private Map<K, S> mappings = new HashMap<>();
|
||||||
|
|
||||||
|
private final List<Filter<C, R, P>> filters = new ArrayList<>();
|
||||||
|
|
||||||
|
protected Filter<C, R, P> headFilter;
|
||||||
|
|
||||||
|
protected void putServlet(S servlet) {
|
||||||
|
synchronized (lock1) {
|
||||||
|
Set<S> newservlets = new HashSet<>(servlets);
|
||||||
|
newservlets.add(servlet);
|
||||||
|
this.servlets = newservlets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeServlet(S servlet) {
|
||||||
|
synchronized (lock1) {
|
||||||
|
Set<S> newservlets = new HashSet<>(servlets);
|
||||||
|
newservlets.remove(servlet);
|
||||||
|
this.servlets = newservlets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsServlet(Class<? extends S> servletClass) {
|
||||||
|
synchronized (lock1) {
|
||||||
|
for (S servlet : new HashSet<>(servlets)) {
|
||||||
|
if (servlet.getClass().equals(servletClass)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsServlet(String servletClassName) {
|
||||||
|
synchronized (lock1) {
|
||||||
|
for (S servlet : new HashSet<>(servlets)) {
|
||||||
|
if (servlet.getClass().getName().equals(servletClassName)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void putMapping(K key, S servlet) {
|
||||||
|
synchronized (lock2) {
|
||||||
|
Map<K, S> newmappings = new HashMap<>(mappings);
|
||||||
|
newmappings.put(key, servlet);
|
||||||
|
this.mappings = newmappings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeMapping(K key) {
|
||||||
|
synchronized (lock2) {
|
||||||
|
if (mappings.containsKey(key)) {
|
||||||
|
Map<K, S> newmappings = new HashMap<>(mappings);
|
||||||
|
newmappings.remove(key);
|
||||||
|
this.mappings = newmappings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeMapping(S servlet) {
|
||||||
|
synchronized (lock2) {
|
||||||
|
List<K> keys = new ArrayList<>();
|
||||||
|
Map<K, S> newmappings = new HashMap<>(mappings);
|
||||||
|
for (Map.Entry<K, S> en : newmappings.entrySet()) {
|
||||||
|
if (en.getValue().equals(servlet)) {
|
||||||
|
keys.add(en.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (K key : keys) newmappings.remove(key);
|
||||||
|
this.mappings = newmappings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected S mappingServlet(K key) {
|
||||||
|
return mappings.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void init(C context, AnyValue config) {
|
||||||
|
synchronized (filters) {
|
||||||
|
if (!filters.isEmpty()) {
|
||||||
|
Collections.sort(filters);
|
||||||
|
for (Filter<C, R, P> filter : filters) {
|
||||||
|
filter.init(context, config);
|
||||||
|
}
|
||||||
|
this.headFilter = filters.get(0);
|
||||||
|
Filter<C, R, P> filter = this.headFilter;
|
||||||
|
for (int i = 1; i < filters.size(); i++) {
|
||||||
|
filter._next = filters.get(i);
|
||||||
|
filter = filter._next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void destroy(C context, AnyValue config) {
|
||||||
|
synchronized (filters) {
|
||||||
|
if (!filters.isEmpty()) {
|
||||||
|
for (Filter filter : filters) {
|
||||||
|
filter.destroy(context, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void addFilter(Filter<C, R, P> filter, AnyValue conf) {
|
||||||
|
filter._conf = conf;
|
||||||
|
synchronized (filters) {
|
||||||
|
this.filters.add(filter);
|
||||||
|
Collections.sort(this.filters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Filter<C, R, P>> T removeFilter(Class<T> filterClass) {
|
||||||
|
return removeFilter(f -> filterClass.equals(f.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsFilter(Class<? extends Filter> filterClass) {
|
||||||
|
if (this.headFilter == null || filterClass == null) return false;
|
||||||
|
Filter filter = this.headFilter;
|
||||||
|
do {
|
||||||
|
if (filter.getClass().equals(filterClass)) return true;
|
||||||
|
} while ((filter = filter._next) != null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsFilter(String filterClassName) {
|
||||||
|
if (this.headFilter == null || filterClassName == null) return false;
|
||||||
|
Filter filter = this.headFilter;
|
||||||
|
do {
|
||||||
|
if (filter.getClass().getName().equals(filterClassName)) return true;
|
||||||
|
} while ((filter = filter._next) != null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends Filter<C, R, P>> T removeFilter(Predicate<T> predicate) {
|
||||||
|
if (this.headFilter == null || predicate == null) return null;
|
||||||
|
synchronized (filters) {
|
||||||
|
Filter filter = this.headFilter;
|
||||||
|
Filter prev = null;
|
||||||
|
do {
|
||||||
|
if (predicate.test((T) filter)) break;
|
||||||
|
prev = filter;
|
||||||
|
} while ((filter = filter._next) != null);
|
||||||
|
if (filter != null) {
|
||||||
|
if (prev == null) {
|
||||||
|
this.headFilter = filter._next;
|
||||||
|
} else {
|
||||||
|
prev._next = filter._next;
|
||||||
|
}
|
||||||
|
filter._next = null;
|
||||||
|
this.filters.remove(filter);
|
||||||
|
}
|
||||||
|
return (T) filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends Filter<C, R, P>> List<T> getFilters() {
|
||||||
|
return (List) new ArrayList<>(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
|
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
|
||||||
|
|
||||||
public final void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
|
public final void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
|
||||||
@@ -47,7 +220,9 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
} else if (rs == 0) {
|
} else if (rs == 0) {
|
||||||
response.context.offerBuffer(buffer);
|
response.context.offerBuffer(buffer);
|
||||||
request.prepare();
|
request.prepare();
|
||||||
this.execute(request, response);
|
response.filter = this.headFilter;
|
||||||
|
response.servlet = this;
|
||||||
|
response.nextEvent();
|
||||||
} else {
|
} else {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
final AtomicInteger ai = new AtomicInteger(rs);
|
final AtomicInteger ai = new AtomicInteger(rs);
|
||||||
@@ -64,7 +239,9 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
response.context.offerBuffer(buffer);
|
response.context.offerBuffer(buffer);
|
||||||
request.prepare();
|
request.prepare();
|
||||||
try {
|
try {
|
||||||
execute(request, response);
|
response.filter = PrepareServlet.this.headFilter;
|
||||||
|
response.servlet = PrepareServlet.this;
|
||||||
|
response.nextEvent();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
illRequestCounter.incrementAndGet();
|
illRequestCounter.incrementAndGet();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
@@ -92,7 +269,7 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
servlet._conf = conf;
|
servlet._conf = conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<S> getServlets() {
|
public List<S> getServlets() {
|
||||||
return new LinkedHashSet<>(servlets);
|
return new ArrayList<>(servlets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,14 +11,30 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 协议底层Server
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
* <p> 详情见: https://redkale.org
|
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public abstract class ProtocolServer {
|
public abstract class ProtocolServer {
|
||||||
|
|
||||||
|
//创建数
|
||||||
|
protected final AtomicLong createCounter = new AtomicLong();
|
||||||
|
|
||||||
|
//关闭数
|
||||||
|
protected final AtomicLong closedCounter = new AtomicLong();
|
||||||
|
|
||||||
|
//在线数
|
||||||
|
protected final AtomicLong livingCounter = new AtomicLong();
|
||||||
|
|
||||||
|
//最大连接数,小于1表示无限制
|
||||||
|
protected int maxconns;
|
||||||
|
|
||||||
public abstract void open() throws IOException;
|
public abstract void open() throws IOException;
|
||||||
|
|
||||||
public abstract void bind(SocketAddress local, int backlog) throws IOException;
|
public abstract void bind(SocketAddress local, int backlog) throws IOException;
|
||||||
@@ -29,10 +45,26 @@ public abstract class ProtocolServer {
|
|||||||
|
|
||||||
public abstract void accept();
|
public abstract void accept();
|
||||||
|
|
||||||
|
public void setMaxconns(int maxconns) {
|
||||||
|
this.maxconns = maxconns;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void close() throws IOException;
|
public abstract void close() throws IOException;
|
||||||
|
|
||||||
public abstract AsynchronousChannelGroup getChannelGroup();
|
public abstract AsynchronousChannelGroup getChannelGroup();
|
||||||
|
|
||||||
|
public long getCreateCount() {
|
||||||
|
return createCounter.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getClosedCount() {
|
||||||
|
return closedCounter.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLivingCount() {
|
||||||
|
return livingCounter.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
public static ProtocolServer create(String protocol, Context context) {
|
public static ProtocolServer create(String protocol, Context context) {
|
||||||
if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context);
|
if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context);
|
||||||
@@ -91,7 +123,7 @@ public abstract class ProtocolServer {
|
|||||||
SocketAddress address = serchannel.receive(buffer);
|
SocketAddress address = serchannel.receive(buffer);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
|
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
|
||||||
context.submit(new PrepareRunner(context, conn, buffer));
|
context.runAsync(new PrepareRunner(context, conn, buffer));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
context.offerBuffer(buffer);
|
context.offerBuffer(buffer);
|
||||||
}
|
}
|
||||||
@@ -116,6 +148,20 @@ public abstract class ProtocolServer {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCreateCount() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getClosedCount() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLivingCount() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class ProtocolTCPServer extends ProtocolServer {
|
private static final class ProtocolTCPServer extends ProtocolServer {
|
||||||
@@ -159,7 +205,19 @@ public abstract class ProtocolServer {
|
|||||||
@Override
|
@Override
|
||||||
public void completed(final AsynchronousSocketChannel channel, Void attachment) {
|
public void completed(final AsynchronousSocketChannel channel, Void attachment) {
|
||||||
serchannel.accept(null, this);
|
serchannel.accept(null, this);
|
||||||
context.submit(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null));
|
if (maxconns > 0 && livingCounter.get() >= maxconns) {
|
||||||
|
try {
|
||||||
|
channel.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createCounter.incrementAndGet();
|
||||||
|
livingCounter.incrementAndGet();
|
||||||
|
AsyncConnection conn = AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond);
|
||||||
|
conn.livingCounter = livingCounter;
|
||||||
|
conn.closedCounter = closedCounter;
|
||||||
|
context.submitAsync(new PrepareRunner(context, conn, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.redkale.convert.bson.BsonConvert;
|
|||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 协议请求对象
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -50,6 +51,7 @@ public abstract class Request<C extends Context> {
|
|||||||
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
||||||
*
|
*
|
||||||
* @param buffer ByteBuffer对象
|
* @param buffer ByteBuffer对象
|
||||||
|
*
|
||||||
* @return 缺少的字节数
|
* @return 缺少的字节数
|
||||||
*/
|
*/
|
||||||
protected abstract int readHeader(ByteBuffer buffer);
|
protected abstract int readHeader(ByteBuffer buffer);
|
||||||
@@ -58,6 +60,7 @@ public abstract class Request<C extends Context> {
|
|||||||
* 读取buffer,并返回读取的有效数据长度
|
* 读取buffer,并返回读取的有效数据长度
|
||||||
*
|
*
|
||||||
* @param buffer ByteBuffer对象
|
* @param buffer ByteBuffer对象
|
||||||
|
*
|
||||||
* @return 有效数据长度
|
* @return 有效数据长度
|
||||||
*/
|
*/
|
||||||
protected abstract int readBody(ByteBuffer buffer);
|
protected abstract int readBody(ByteBuffer buffer);
|
||||||
@@ -81,8 +84,9 @@ public abstract class Request<C extends Context> {
|
|||||||
return (T) properties.get(name);
|
return (T) properties.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
protected <T> T removeProperty(String name) {
|
protected <T> T removeProperty(String name) {
|
||||||
return (T)properties.remove(name);
|
return (T) properties.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, Object> getProperties() {
|
protected Map<String, Object> getProperties() {
|
||||||
@@ -99,8 +103,9 @@ public abstract class Request<C extends Context> {
|
|||||||
return (T) attributes.get(name);
|
return (T) attributes.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T removeAttribute(String name) {
|
public <T> T removeAttribute(String name) {
|
||||||
return (T)attributes.remove(name);
|
return (T) attributes.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> getAttributes() {
|
public Map<String, Object> getAttributes() {
|
||||||
|
|||||||
@@ -5,11 +5,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.net;
|
package org.redkale.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 协议响应对象
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
@@ -33,6 +36,10 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
|
|
||||||
protected BiConsumer<R, Response<C, R>> recycleListener;
|
protected BiConsumer<R, Response<C, R>> recycleListener;
|
||||||
|
|
||||||
|
protected Filter<C, R, ? extends Response<C, R>> filter;
|
||||||
|
|
||||||
|
protected Servlet<C, R, ? extends Response<C, R>> servlet;
|
||||||
|
|
||||||
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
|
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -107,16 +114,17 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
try {
|
try {
|
||||||
recycleListener.accept(request, this);
|
recycleListener.accept(request, this);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println(request);
|
context.logger.log(Level.WARNING, "Response.recycleListener error, request = " + request, e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
recycleListener = null;
|
recycleListener = null;
|
||||||
}
|
}
|
||||||
this.output = null;
|
this.output = null;
|
||||||
|
this.filter = null;
|
||||||
|
this.servlet = null;
|
||||||
request.recycle();
|
request.recycle();
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
if (keepAlive) {
|
if (keepAlive) {
|
||||||
this.context.submit(new PrepareRunner(context, channel, null));
|
this.context.runAsync(new PrepareRunner(context, channel, null));
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
if (channel.isOpen()) channel.close();
|
if (channel.isOpen()) channel.close();
|
||||||
@@ -139,7 +147,30 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
this.request.createtime = System.currentTimeMillis();
|
this.request.createtime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRecycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
|
protected void setFilter(Filter<C, R, Response<C, R>> filter) {
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void thenEvent(Servlet servlet) {
|
||||||
|
this.servlet = servlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void nextEvent() throws IOException {
|
||||||
|
if (this.filter != null) {
|
||||||
|
Filter runner = this.filter;
|
||||||
|
this.filter = this.filter._next;
|
||||||
|
runner.doFilter(request, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.servlet != null) {
|
||||||
|
Servlet s = this.servlet;
|
||||||
|
this.servlet = null;
|
||||||
|
s.execute(request, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
|
||||||
this.recycleListener = recycleListener;
|
this.recycleListener = recycleListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,30 +178,56 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已关闭
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isClosed() {
|
||||||
|
return !this.inited;
|
||||||
|
}
|
||||||
|
|
||||||
public void finish() {
|
public void finish() {
|
||||||
this.finish(false);
|
this.finish(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(boolean kill) {
|
public void finish(boolean kill) {
|
||||||
|
if (!this.inited) return; //避免重复关闭
|
||||||
//System.println("耗时: " + (System.currentTimeMillis() - request.createtime));
|
//System.println("耗时: " + (System.currentTimeMillis() - request.createtime));
|
||||||
if (kill) refuseAlive();
|
if (kill) refuseAlive();
|
||||||
this.context.responsePool.offer(this);
|
this.context.responsePool.offer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void finish(final byte[] bs) {
|
||||||
|
if (!this.inited) return; //避免重复关闭
|
||||||
|
if (this.context.bufferCapacity == bs.length) {
|
||||||
|
ByteBuffer buffer = this.context.pollBuffer();
|
||||||
|
buffer.put(bs);
|
||||||
|
buffer.flip();
|
||||||
|
this.finish(buffer);
|
||||||
|
} else {
|
||||||
|
this.finish(ByteBuffer.wrap(bs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void finish(ByteBuffer buffer) {
|
public void finish(ByteBuffer buffer) {
|
||||||
|
if (!this.inited) return; //避免重复关闭
|
||||||
this.channel.write(buffer, buffer, finishHandler);
|
this.channel.write(buffer, buffer, finishHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(boolean kill, ByteBuffer buffer) {
|
public void finish(boolean kill, ByteBuffer buffer) {
|
||||||
|
if (!this.inited) return; //避免重复关闭
|
||||||
if (kill) refuseAlive();
|
if (kill) refuseAlive();
|
||||||
this.channel.write(buffer, buffer, finishHandler);
|
this.channel.write(buffer, buffer, finishHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(ByteBuffer... buffers) {
|
public void finish(ByteBuffer... buffers) {
|
||||||
|
if (!this.inited) return; //避免重复关闭
|
||||||
this.channel.write(buffers, buffers, finishHandler2);
|
this.channel.write(buffers, buffers, finishHandler2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(boolean kill, ByteBuffer... buffers) {
|
public void finish(boolean kill, ByteBuffer... buffers) {
|
||||||
|
if (!this.inited) return; //避免重复关闭
|
||||||
if (kill) refuseAlive();
|
if (kill) refuseAlive();
|
||||||
this.channel.write(buffers, buffers, finishHandler2);
|
this.channel.write(buffers, buffers, finishHandler2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
package org.redkale.net;
|
package org.redkale.net;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.text.*;
|
import java.text.*;
|
||||||
@@ -14,8 +13,7 @@ import java.util.*;
|
|||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.redkale.util.AnyValue;
|
import org.redkale.util.*;
|
||||||
import org.redkale.watch.WatchFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -39,9 +37,6 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
//服务的启动时间
|
//服务的启动时间
|
||||||
protected final long serverStartTime;
|
protected final long serverStartTime;
|
||||||
|
|
||||||
//监控对象
|
|
||||||
protected final WatchFactory watch;
|
|
||||||
|
|
||||||
//服务的名称
|
//服务的名称
|
||||||
protected String name;
|
protected String name;
|
||||||
|
|
||||||
@@ -76,7 +71,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
protected int threads;
|
protected int threads;
|
||||||
|
|
||||||
//线程池
|
//线程池
|
||||||
protected ExecutorService executor;
|
protected ThreadPoolExecutor executor;
|
||||||
|
|
||||||
//ByteBuffer池大小
|
//ByteBuffer池大小
|
||||||
protected int bufferPoolSize;
|
protected int bufferPoolSize;
|
||||||
@@ -93,11 +88,13 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
//IO写入 的超时秒数,小于1视为不设置
|
//IO写入 的超时秒数,小于1视为不设置
|
||||||
protected int writeTimeoutSecond;
|
protected int writeTimeoutSecond;
|
||||||
|
|
||||||
protected Server(long serverStartTime, String protocol, PrepareServlet<K, C, R, P, S> servlet, final WatchFactory watch) {
|
//最大连接数
|
||||||
|
protected int maxconns;
|
||||||
|
|
||||||
|
protected Server(long serverStartTime, String protocol, PrepareServlet<K, C, R, P, S> servlet) {
|
||||||
this.serverStartTime = serverStartTime;
|
this.serverStartTime = serverStartTime;
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
this.prepare = servlet;
|
this.prepare = servlet;
|
||||||
this.watch = watch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(final AnyValue config) throws Exception {
|
public void init(final AnyValue config) throws Exception {
|
||||||
@@ -105,11 +102,13 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
this.config = config;
|
this.config = config;
|
||||||
this.address = new InetSocketAddress(config.getValue("host", "0.0.0.0"), config.getIntValue("port", 80));
|
this.address = new InetSocketAddress(config.getValue("host", "0.0.0.0"), config.getIntValue("port", 80));
|
||||||
this.charset = Charset.forName(config.getValue("charset", "UTF-8"));
|
this.charset = Charset.forName(config.getValue("charset", "UTF-8"));
|
||||||
this.backlog = config.getIntValue("backlog", 8 * 1024);
|
this.maxconns = config.getIntValue("maxconns", 0);
|
||||||
this.readTimeoutSecond = config.getIntValue("readTimeoutSecond", 0);
|
this.readTimeoutSecond = config.getIntValue("readTimeoutSecond", 0);
|
||||||
this.writeTimeoutSecond = config.getIntValue("writeTimeoutSecond", 0);
|
this.writeTimeoutSecond = config.getIntValue("writeTimeoutSecond", 0);
|
||||||
this.maxbody = config.getIntValue("maxbody", 64 * 1024);
|
this.backlog = parseLenth(config.getValue("backlog"), 8 * 1024);
|
||||||
this.bufferCapacity = config.getIntValue("bufferCapacity", 8 * 1024);
|
this.maxbody = parseLenth(config.getValue("maxbody"), 64 * 1024);
|
||||||
|
int bufCapacity = parseLenth(config.getValue("bufferCapacity"), 8 * 1024);
|
||||||
|
this.bufferCapacity = bufCapacity < 256 ? 256 : bufCapacity;
|
||||||
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 16);
|
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 16);
|
||||||
this.bufferPoolSize = config.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 512);
|
this.bufferPoolSize = config.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 512);
|
||||||
this.responsePoolSize = config.getIntValue("responsePoolSize", Runtime.getRuntime().availableProcessors() * 256);
|
this.responsePoolSize = config.getIntValue("responsePoolSize", Runtime.getRuntime().availableProcessors() * 256);
|
||||||
@@ -118,13 +117,31 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
final AtomicInteger counter = new AtomicInteger();
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
final Format f = createFormat();
|
final Format f = createFormat();
|
||||||
final String n = name;
|
final String n = name;
|
||||||
this.executor = Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threads, (Runnable r) -> {
|
||||||
Thread t = new WorkThread(executor, r);
|
Thread t = new WorkThread(executor, r);
|
||||||
t.setName(n + "-ServletThread-" + f.format(counter.incrementAndGet()));
|
t.setName(n + "-ServletThread-" + f.format(counter.incrementAndGet()));
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static int parseLenth(String value, int defValue) {
|
||||||
|
if (value == null) return defValue;
|
||||||
|
value = value.toUpperCase().replace("B", "");
|
||||||
|
if (value.endsWith("G")) return Integer.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
|
||||||
|
if (value.endsWith("M")) return Integer.decode(value.replace("M", "")) * 1024 * 1024;
|
||||||
|
if (value.endsWith("K")) return Integer.decode(value.replace("K", "")) * 1024;
|
||||||
|
return Integer.decode(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static long parseLenth(String value, long defValue) {
|
||||||
|
if (value == null) return defValue;
|
||||||
|
value = value.toUpperCase().replace("B", "");
|
||||||
|
if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
|
||||||
|
if (value.endsWith("M")) return Long.decode(value.replace("M", "")) * 1024 * 1024;
|
||||||
|
if (value.endsWith("K")) return Long.decode(value.replace("K", "")) * 1024;
|
||||||
|
return Long.decode(value);
|
||||||
|
}
|
||||||
|
|
||||||
public void destroy(final AnyValue config) throws Exception {
|
public void destroy(final AnyValue config) throws Exception {
|
||||||
this.prepare.destroy(context, config);
|
this.prepare.destroy(context, config);
|
||||||
}
|
}
|
||||||
@@ -153,6 +170,13 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
return this.context;
|
return this.context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setThreads(int threads) {
|
||||||
|
int oldthreads = this.threads;
|
||||||
|
this.context.executor.setCorePoolSize(threads);
|
||||||
|
this.threads = threads;
|
||||||
|
logger.info("[" + Thread.currentThread().getName() + "] " + this.getClass().getSimpleName() + " change threads from " + oldthreads + " to " + threads);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void addServlet(S servlet, final Object attachment, AnyValue conf, K... mappings) {
|
public void addServlet(S servlet, final Object attachment, AnyValue conf, K... mappings) {
|
||||||
this.prepare.addServlet(servlet, attachment, conf, mappings);
|
this.prepare.addServlet(servlet, attachment, conf, mappings);
|
||||||
@@ -161,14 +185,14 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
this.context = this.createContext();
|
this.context = this.createContext();
|
||||||
this.prepare.init(this.context, config);
|
this.prepare.init(this.context, config);
|
||||||
if (this.watch != null) this.watch.inject(this.prepare);
|
|
||||||
this.serverChannel = ProtocolServer.create(this.protocol, context);
|
this.serverChannel = ProtocolServer.create(this.protocol, context);
|
||||||
this.serverChannel.open();
|
this.serverChannel.open();
|
||||||
if (this.serverChannel.supportedOptions().contains(StandardSocketOptions.TCP_NODELAY)) {
|
if (this.serverChannel.supportedOptions().contains(StandardSocketOptions.TCP_NODELAY)) {
|
||||||
this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
||||||
}
|
}
|
||||||
serverChannel.bind(address, backlog);
|
serverChannel.bind(address, backlog);
|
||||||
serverChannel.accept();
|
serverChannel.setMaxconns(this.maxconns);
|
||||||
|
serverChannel.accept();
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol)) + " listen: " + address
|
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol)) + " listen: " + address
|
||||||
+ ", threads: " + threads + ", bufferCapacity: " + bufferCapacity + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
|
+ ", threads: " + threads + ", bufferCapacity: " + bufferCapacity + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
|
||||||
@@ -190,6 +214,76 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
logger.info(this.getClass().getSimpleName() + " shutdown in " + e + " ms");
|
logger.info(this.getClass().getSimpleName() + " shutdown in " + e + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在Filter
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param filterClass Filter类
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public <T extends Filter> boolean containsFilter(Class<T> filterClass) {
|
||||||
|
return this.prepare.containsFilter(filterClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在Filter
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param filterClassName Filter类
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public <T extends Filter> boolean containsFilter(String filterClassName) {
|
||||||
|
return this.prepare.containsFilter(filterClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在Servlet
|
||||||
|
*
|
||||||
|
* @param servletClass Servlet类
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean containsServlet(Class<? extends S> servletClass) {
|
||||||
|
return this.prepare.containsServlet(servletClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在Servlet
|
||||||
|
*
|
||||||
|
* @param servletClassName Servlet类
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean containsServlet(String servletClassName) {
|
||||||
|
return this.prepare.containsServlet(servletClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁Servlet
|
||||||
|
*
|
||||||
|
* @param servlet Servlet
|
||||||
|
*/
|
||||||
|
public void destroyServlet(S servlet) {
|
||||||
|
servlet.destroy(context, this.prepare.getServletConf(servlet));
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建数
|
||||||
|
public long getCreateConnectionCount() {
|
||||||
|
return serverChannel == null ? -1 : serverChannel.getCreateCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
//关闭数
|
||||||
|
public long getClosedConnectionCount() {
|
||||||
|
return serverChannel == null ? -1 : serverChannel.getClosedCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
//在线数
|
||||||
|
public long getLivingConnectionCount() {
|
||||||
|
return serverChannel == null ? -1 : serverChannel.getLivingCount();
|
||||||
|
}
|
||||||
|
|
||||||
protected Format createFormat() {
|
protected Format createFormat() {
|
||||||
String sf = "0";
|
String sf = "0";
|
||||||
if (this.threads > 10) sf = "00";
|
if (this.threads > 10) sf = "00";
|
||||||
@@ -198,7 +292,7 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
return new DecimalFormat(sf);
|
return new DecimalFormat(sf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static URL[] loadLib(final Logger logger, final String lib) throws Exception {
|
public static URL[] loadLib(final RedkaleClassLoader classLoader, final Logger logger, final String lib) throws Exception {
|
||||||
if (lib == null || lib.isEmpty()) return new URL[0];
|
if (lib == null || lib.isEmpty()) return new URL[0];
|
||||||
final Set<URL> set = new HashSet<>();
|
final Set<URL> set = new HashSet<>();
|
||||||
for (String s : lib.split(";")) {
|
for (String s : lib.split(";")) {
|
||||||
@@ -216,17 +310,8 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (set.isEmpty()) return new URL[0];
|
if (set.isEmpty()) return new URL[0];
|
||||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
for (URL url : set) {
|
||||||
if (cl instanceof URLClassLoader) {
|
classLoader.addURL(url);
|
||||||
URLClassLoader loader = (URLClassLoader) cl;
|
|
||||||
final Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
|
||||||
method.setAccessible(true);
|
|
||||||
for (URL url : set) {
|
|
||||||
method.invoke(loader, url);
|
|
||||||
//if (logger != null) logger.log(Level.INFO, "Server found ClassPath({0})", url);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Thread.currentThread().setContextClassLoader(new URLClassLoader(set.toArray(new URL[set.size()]), cl));
|
|
||||||
}
|
}
|
||||||
List<URL> list = new ArrayList<>(set);
|
List<URL> list = new ArrayList<>(set);
|
||||||
Collections.sort(list, (URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));
|
Collections.sort(list, (URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user