Compare commits
1853 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13a4264488 | ||
|
|
7ffb65cc38 | ||
|
|
2464c360c0 | ||
|
|
1917ccf35c | ||
|
|
4f9c14da97 | ||
|
|
58e23c1b8c | ||
|
|
34156fc092 | ||
|
|
86fde56129 | ||
|
|
d997d3a7bb | ||
|
|
4e689855f4 | ||
|
|
eace16d7fd | ||
|
|
53b7f9b26f | ||
|
|
983c667725 | ||
|
|
96fd660d46 | ||
|
|
7d1770da8a | ||
|
|
b83f6867f3 | ||
|
|
fa7db42f50 | ||
|
|
80c07a5c5b | ||
|
|
59a4c85aeb | ||
|
|
7fc01d38e8 | ||
|
|
3010422f4e | ||
|
|
1f78bb1a98 | ||
|
|
1d7f32efe4 | ||
|
|
1e3d980437 | ||
|
|
8654b5eef8 | ||
|
|
5781ad1de0 | ||
|
|
e2a1fa15d3 | ||
|
|
50da7413d8 | ||
|
|
e45b945024 | ||
|
|
f3668a77ef | ||
|
|
2aee6cab20 | ||
|
|
6233a0b960 | ||
|
|
0ae469d8e2 | ||
|
|
bcad47ebd5 | ||
|
|
71d179b8c3 | ||
|
|
af35e5100e | ||
|
|
96c97c7dd2 | ||
|
|
d5a41fc8b6 | ||
|
|
c3c3afb3c3 | ||
|
|
4f32dcda16 | ||
|
|
67717e73ad | ||
|
|
1753734581 | ||
|
|
3e408e535c | ||
|
|
f154292cb5 | ||
|
|
ac261533c3 | ||
|
|
1982c984ee | ||
|
|
fb5f82c44f | ||
|
|
840cea06db | ||
|
|
3237e2488e | ||
|
|
98e1e40e18 | ||
|
|
def3fc7b2e | ||
|
|
6057b8f90a | ||
|
|
2847f761bb | ||
|
|
b0a2d2ad80 | ||
|
|
564b814f77 | ||
|
|
433585a231 | ||
|
|
6a4750e302 | ||
|
|
748a6f11c1 | ||
|
|
bdd9a82682 | ||
|
|
c551c157d1 | ||
|
|
7e777229ba | ||
|
|
612bfcba37 | ||
|
|
c44e00a100 | ||
|
|
7f46b3194a | ||
|
|
50b7999dee | ||
|
|
871f84b1ff | ||
|
|
4018a95af0 | ||
|
|
ffe3ff5830 | ||
|
|
9b9b0ab10e | ||
|
|
b19e5fe839 | ||
|
|
f6caf41960 | ||
|
|
67d57de166 | ||
|
|
4d79f17a3a | ||
|
|
245d6d6fc7 | ||
|
|
66bd1feadf | ||
|
|
c02e3549eb | ||
|
|
210b8dcf9d | ||
|
|
bbefa788fd | ||
|
|
2f6eb0908e | ||
|
|
51e4d44fc1 | ||
|
|
ed502daeb9 | ||
|
|
d7da527bd5 | ||
|
|
7c5146bc97 | ||
|
|
91cdf9990b | ||
|
|
7d03609462 | ||
|
|
7be9a06e76 | ||
|
|
3eaecacac0 | ||
|
|
9c5e23090c | ||
|
|
c7b05e530d | ||
|
|
889fa25e58 | ||
|
|
da6945224f | ||
|
|
026a727480 | ||
|
|
2404f547ab | ||
|
|
a9dd82dcf4 | ||
|
|
95443be313 | ||
|
|
5d1805b10e | ||
|
|
72eb175dc3 | ||
|
|
d5cbcaaa15 | ||
|
|
bfa722f6da | ||
|
|
6b9d35983a | ||
|
|
6cf50c7cc9 | ||
|
|
cf05851752 | ||
|
|
1cbbf17392 | ||
|
|
96afeb19b2 | ||
|
|
56da72b16e | ||
|
|
b781868876 | ||
|
|
6a05f4b497 | ||
|
|
b9fa617374 | ||
|
|
c59baee1f5 | ||
|
|
98531d6b2f | ||
|
|
8df5b45525 | ||
|
|
ebba966d52 | ||
|
|
169f35d41f | ||
|
|
8bec9e88a7 | ||
|
|
854aa0153f | ||
|
|
77eaaae6ce | ||
|
|
fd7badec0a | ||
|
|
a834b6ea21 | ||
|
|
31fad72172 | ||
|
|
ef14195e71 | ||
|
|
a2fab32356 | ||
|
|
2dd0ecfa49 | ||
|
|
849fe15728 | ||
|
|
76afab3c78 | ||
|
|
21250794f5 | ||
|
|
9f85ceb2ed | ||
|
|
b6ecdef0c5 | ||
|
|
4dfd528533 | ||
|
|
3131601477 | ||
|
|
5921cf5f0d | ||
|
|
788f7d5eb1 | ||
|
|
79cb79481e | ||
|
|
41f0061dca | ||
|
|
f981e4f886 | ||
|
|
ebf30e488a | ||
|
|
7ab889baac | ||
|
|
8d9d893839 | ||
|
|
205233f8c9 | ||
|
|
6ee9527ed9 | ||
|
|
ee56ffa346 | ||
|
|
3fcc478356 | ||
|
|
26e4cd2f4a | ||
|
|
509524144d | ||
|
|
676285e20b | ||
|
|
43edb0f814 | ||
|
|
1c684a4e32 | ||
|
|
156af0e2a4 | ||
|
|
28d9c465fd | ||
|
|
a285510656 | ||
|
|
d6042d142e | ||
|
|
be8d368e72 | ||
|
|
75698d9390 | ||
|
|
9d343694cc | ||
|
|
fddb2a3be0 | ||
|
|
3b44eddbb9 | ||
|
|
ba4100e22d | ||
|
|
72155e31dd | ||
|
|
60903c844e | ||
|
|
5c810b5ff6 | ||
|
|
e3a8c2d392 | ||
|
|
1f27d5f3e3 | ||
|
|
abb790da54 | ||
|
|
f4a2f2af94 | ||
|
|
29a21d060b | ||
|
|
de19861974 | ||
|
|
e5766e31dc | ||
|
|
fca727ecaf | ||
|
|
d009c9b2ed | ||
|
|
fd2e84f781 | ||
|
|
2b7676449d | ||
|
|
4b2c6eba63 | ||
|
|
84147280cf | ||
|
|
e62d9f8201 | ||
|
|
4cec4e64f9 | ||
|
|
9eb647428c | ||
|
|
b68808b325 | ||
|
|
a9dce0efbf | ||
|
|
de63f81238 | ||
|
|
a05afe45c0 | ||
|
|
236996caa1 | ||
|
|
b808c93885 | ||
|
|
7865b74359 | ||
|
|
143e1880d4 | ||
|
|
1be467cfe9 | ||
|
|
7f8f157616 | ||
|
|
c140ad6828 | ||
|
|
50e41dba25 | ||
|
|
c73fc5f266 | ||
|
|
a5f3adc477 | ||
|
|
b77764c1cf | ||
|
|
714b188560 | ||
|
|
47315f188a | ||
|
|
384a8a3991 | ||
|
|
7a80c00439 | ||
|
|
43486ce1e2 | ||
|
|
627c1e953e | ||
|
|
da141cc6bd | ||
|
|
8f3a9a6297 | ||
|
|
e8d496b0ad | ||
|
|
f5accfbe8f | ||
|
|
16e291036e | ||
|
|
a79b8b77b5 | ||
|
|
8e2d6acdf8 | ||
|
|
70c5123f7a | ||
|
|
7cfbaee199 | ||
|
|
fa8d78e18f | ||
|
|
4f5e72a31a | ||
|
|
7c5822fb7c | ||
|
|
60df140bfd | ||
|
|
f41e905842 | ||
|
|
9824fe6da3 | ||
|
|
1fb37f4b67 | ||
|
|
a8a6861a21 | ||
|
|
614222bdc3 | ||
|
|
8e98dda795 | ||
|
|
3686306505 | ||
|
|
d29aa78022 | ||
|
|
85fa406e1d | ||
|
|
d501e2016f | ||
|
|
cf0cd66ac9 | ||
|
|
c921f657b1 | ||
|
|
c93c1d84c5 | ||
|
|
2e66b1a546 | ||
|
|
48629146ed | ||
|
|
a6c8502416 | ||
|
|
fc74dc33c1 | ||
|
|
73de9dfc33 | ||
|
|
68d78a4aa4 | ||
|
|
b618e0e884 | ||
|
|
2d1a6e0edc | ||
|
|
76a7e92787 | ||
|
|
a2178b9a5f | ||
|
|
dcf0fecdb0 | ||
|
|
f88db8abf9 | ||
|
|
0c8b0f5e19 | ||
|
|
b794872147 | ||
|
|
86614f035b | ||
|
|
5f3a472c5e | ||
|
|
7eb2a405d3 | ||
|
|
1d030183bb | ||
|
|
d211692306 | ||
|
|
86c7d95c80 | ||
|
|
e99d43b25c | ||
|
|
730fc0a911 | ||
|
|
1ea92d7165 | ||
|
|
0dfc0ca853 | ||
|
|
474f82b3cf | ||
|
|
ae80109c77 | ||
|
|
807fe63cbe | ||
|
|
44ed3259f9 | ||
|
|
93b2b5fab8 | ||
|
|
58e807439c | ||
|
|
ca2f34bfac | ||
|
|
b8719d7f76 | ||
|
|
be0fdd9045 | ||
|
|
1d2b583c0c | ||
|
|
9def35e2e1 | ||
|
|
a11127ea58 | ||
|
|
af80864e08 | ||
|
|
f6a4fbdf87 | ||
|
|
61f48be2a6 | ||
|
|
8516925537 | ||
|
|
f828ec3d08 | ||
|
|
1eb1706166 | ||
|
|
ffd3b6daf6 | ||
|
|
76d538264a | ||
|
|
02d0a06195 | ||
|
|
c43325e402 | ||
|
|
63bc4b2d00 | ||
|
|
6e5da92263 | ||
|
|
6358719255 | ||
|
|
bdfd92299a | ||
|
|
aa4c9896ba | ||
|
|
1549f1feed | ||
|
|
2a9a713f3e | ||
|
|
0377dac71f | ||
|
|
13217a11c0 | ||
|
|
146b81ee5e | ||
|
|
8502792aad | ||
|
|
3d9447327a | ||
|
|
288fc67621 | ||
|
|
d4bc751a20 | ||
|
|
4cf160e5d3 | ||
|
|
98f29d6a6e | ||
|
|
92bb0a561b | ||
|
|
1329f6f0e1 | ||
|
|
a3dbfaba88 | ||
|
|
2032f39bf9 | ||
|
|
8840415739 | ||
|
|
bdf2fd21c3 | ||
|
|
bd1e326404 | ||
|
|
ebd31bc3d3 | ||
|
|
7185191d91 | ||
|
|
1a1dd44f34 | ||
|
|
95fd147268 | ||
|
|
88657fdf63 | ||
|
|
03de684940 | ||
|
|
b445b99572 | ||
|
|
bd4343c5d8 | ||
|
|
a58c13cd9f | ||
|
|
cf23ecc12c | ||
|
|
86754c2324 | ||
|
|
e6f0a8fdf3 | ||
|
|
fa9fc531d0 | ||
|
|
30bf2c1ad3 | ||
|
|
d326da9344 | ||
|
|
8f6494163d | ||
|
|
490cabefb2 | ||
|
|
66ff86d6fb | ||
|
|
0e5479d55e | ||
|
|
3eb3e0104d | ||
|
|
079e6116b2 | ||
|
|
b6a3adb21c | ||
|
|
ecf831c0f5 | ||
|
|
adfa0be79e | ||
|
|
7ec91802b2 | ||
|
|
1e15eb31c7 | ||
|
|
8d5e61a9a2 | ||
|
|
64500b113a | ||
|
|
a7e5fad571 | ||
|
|
531b00b6fd | ||
|
|
ce3fc5792b | ||
|
|
a477b2fb73 | ||
|
|
6a5d121615 | ||
|
|
90960e0574 | ||
|
|
b6980f7cf8 | ||
|
|
2fb3472de0 | ||
|
|
6dacbafc29 | ||
|
|
f1fcbd7396 | ||
|
|
681e389f19 | ||
|
|
06b7274364 | ||
|
|
b4f7de4858 | ||
|
|
6261232ce6 | ||
|
|
eb35b90950 | ||
|
|
958cea4e0d | ||
|
|
7f184bae50 | ||
|
|
3d68103a19 | ||
|
|
612851bce0 | ||
|
|
e365dae9e4 | ||
|
|
b6d5fc02dc | ||
|
|
59d139ace2 | ||
|
|
1d7a72f992 | ||
|
|
45f2ce261e | ||
|
|
f79e49db5a | ||
|
|
218aebaa0f | ||
|
|
f11870d6bc | ||
|
|
ebea6bb92c | ||
|
|
4806d6ada0 | ||
|
|
6909748bda | ||
|
|
982fc8440c | ||
|
|
e4df07a00c | ||
|
|
0ee30aca7e | ||
|
|
b994bcbcfb | ||
|
|
cc23b44409 | ||
|
|
de36ef697d | ||
|
|
e0d224a330 | ||
|
|
adc2106bec | ||
|
|
6cdbe957a7 | ||
|
|
14808cb01c | ||
|
|
1edadbfee8 | ||
|
|
043a23ecdf | ||
|
|
383ef37989 | ||
|
|
9cd9a8d3ea | ||
|
|
db8c94f433 | ||
|
|
22fb3e5bef | ||
|
|
6329722f17 | ||
|
|
2dee61223d | ||
|
|
f83fc52e9c | ||
|
|
2f8a04c15d | ||
|
|
a1501af7a7 | ||
|
|
a1fdfc9cc9 | ||
|
|
2dddf3c2a5 | ||
|
|
84061cf60f | ||
|
|
557c2c7858 | ||
|
|
cb2d355bc9 | ||
|
|
ed1b642d5b | ||
|
|
411f5e1951 | ||
|
|
450506ca96 | ||
|
|
bf700aa88f | ||
|
|
c108ab196c | ||
|
|
cac8662c01 | ||
|
|
197c58ef98 | ||
|
|
d4c2723759 | ||
|
|
c34a6d8f49 | ||
|
|
5de580c00b | ||
|
|
ed1fb151d7 | ||
|
|
4c4913c5d0 | ||
|
|
adb0dc5963 | ||
|
|
740bc8ae31 | ||
|
|
30a0b12020 | ||
|
|
b0b8b0db3b | ||
|
|
71244732f2 | ||
|
|
820af60c19 | ||
|
|
b3252359bd | ||
|
|
9ade568597 | ||
|
|
cf5224a5f6 | ||
|
|
6c4a83d14d | ||
|
|
0439b95139 | ||
|
|
72a618a0b7 | ||
|
|
0f7520e67b | ||
|
|
fcd69474a2 | ||
|
|
3130e00bab | ||
|
|
1c063b57ec | ||
|
|
efeff3b720 | ||
|
|
ea15634f47 | ||
|
|
e744d001c6 | ||
|
|
06e486e5e2 | ||
|
|
95180ffdef | ||
|
|
e5bd85e9aa | ||
|
|
ec4ec2ff77 | ||
|
|
5a1c9215bc | ||
|
|
53457b73ad | ||
|
|
8cb9fcf01a | ||
|
|
2c88b0e75e | ||
|
|
4daffdc31f | ||
|
|
16dec2cde5 | ||
|
|
82e5fb593e | ||
|
|
4a60ecb3ff | ||
|
|
38307405ed | ||
|
|
fe332d0cbd | ||
|
|
e45f75c1d6 | ||
|
|
a77f450757 | ||
|
|
9f8e946ea3 | ||
|
|
7633687665 | ||
|
|
a1e37643d0 | ||
|
|
8440b58d6c | ||
|
|
a97f8efe21 | ||
|
|
d83e7c22ac | ||
|
|
01a5b32b22 | ||
|
|
8834f57582 | ||
|
|
57fd7b96b4 | ||
|
|
14fe2fbc84 | ||
|
|
0b86edb654 | ||
|
|
07ab74902c | ||
|
|
e4c6e860c1 | ||
|
|
02cf587fcf | ||
|
|
081773163b | ||
|
|
292ff63699 | ||
|
|
f1a97c0219 | ||
|
|
e545010034 | ||
|
|
ef57fa9a25 | ||
|
|
1bd0d891a4 | ||
|
|
9a51c1de1d | ||
|
|
e4bb75dd8e | ||
|
|
66e1e08ae2 | ||
|
|
708cd5a644 | ||
|
|
138c9aba97 | ||
|
|
e5e17b4496 | ||
|
|
cadaebefb9 | ||
|
|
e2fb7935f6 | ||
|
|
16b3dab600 | ||
|
|
758972890e | ||
|
|
a88285d935 | ||
|
|
d7832fb931 | ||
|
|
f073c9a0bc | ||
|
|
63ef83ec62 | ||
|
|
51c50415e1 | ||
|
|
2f08fa6476 | ||
|
|
3091972fc5 | ||
|
|
8e14df9a95 | ||
|
|
683cec6f4d | ||
|
|
ec6e5aa3b1 | ||
|
|
f4c00a9b6f | ||
|
|
c071ec5d6c | ||
|
|
29148c4b42 | ||
|
|
7340caa4a9 | ||
|
|
7d23dfa73d | ||
|
|
19932820a9 | ||
|
|
6b59c54087 | ||
|
|
58f5ee999a | ||
|
|
32e8c033ea | ||
|
|
84a96f750f | ||
|
|
6560e71e48 | ||
|
|
ee8a18a528 | ||
|
|
c36fc36964 | ||
|
|
a34f85bfc9 | ||
|
|
6f00efa077 | ||
|
|
469dff8478 | ||
|
|
c50eb79b1d | ||
|
|
985bf6ed25 | ||
|
|
bd51696e08 | ||
|
|
2764d59a4f | ||
|
|
c1509bb712 | ||
|
|
b14f32deb3 | ||
|
|
62145a2aad | ||
|
|
8fb88a57b2 | ||
|
|
44f12ae003 | ||
|
|
bf97ef3a08 | ||
|
|
aeefc3b8a2 | ||
|
|
5763718816 | ||
|
|
3b142b7504 | ||
|
|
0f52d32424 | ||
|
|
f5f3c48f38 | ||
|
|
9f9f5aa000 | ||
|
|
be4ca0287b | ||
|
|
a84ed72f28 | ||
|
|
8eb5f56f42 | ||
|
|
df1aa2b379 | ||
|
|
da2befcb97 | ||
|
|
92d0f7e796 | ||
|
|
6aa3949d05 | ||
|
|
fa833d9224 | ||
|
|
c9261f8475 | ||
|
|
a1df62af08 | ||
|
|
aa12413f4e | ||
|
|
2ccd9ba10f | ||
|
|
81ae68c571 | ||
|
|
51b45f4713 | ||
|
|
66e1f58879 | ||
|
|
06bb5180cf | ||
|
|
d83d7f879c | ||
|
|
b8e92c949e | ||
|
|
91548a0ca9 | ||
|
|
dbca25cd54 | ||
|
|
539ea15ae5 | ||
|
|
ad1d9f33d4 | ||
|
|
df98c1a58e | ||
|
|
56d1969c96 | ||
|
|
4b341436af | ||
|
|
4d3d73b4c1 | ||
|
|
55ab279e7f | ||
|
|
82ab994608 | ||
|
|
1c4035e677 | ||
|
|
afdc9e7207 | ||
|
|
9b83abb06a | ||
|
|
26d1a10bd0 | ||
|
|
7e55dcc46d | ||
|
|
45802d2403 | ||
|
|
3660a2a4e5 | ||
|
|
bed81bd93d | ||
|
|
131855cdc5 | ||
|
|
8b69e7d02b | ||
|
|
02a10bf014 | ||
|
|
004b83172e | ||
|
|
fee4555cef | ||
|
|
758bd7de72 | ||
|
|
b2dd366640 | ||
|
|
934c82eadd | ||
|
|
c7ed6574cc | ||
|
|
2ea2667fa7 | ||
|
|
34ae2d38c5 | ||
|
|
a1c95544cb | ||
|
|
c6dc38c35c | ||
|
|
39203ab598 | ||
|
|
51a95a84aa | ||
|
|
8a8d45e642 | ||
|
|
52eb7dbc0c | ||
|
|
0e14b60f12 | ||
|
|
d373ab7204 | ||
|
|
4f9a563ba7 | ||
|
|
852da19b1e | ||
|
|
ddfc040a53 | ||
|
|
df3ccb763a | ||
|
|
f42561ca93 | ||
|
|
580e28519a | ||
|
|
9ecc1d8f19 | ||
|
|
40629ed7b9 | ||
|
|
5790135add | ||
|
|
fd862ed6c6 | ||
|
|
33763af96c | ||
|
|
7c05df3cfb | ||
|
|
f471e2d4c5 | ||
|
|
d4fd093521 | ||
|
|
40003c7789 | ||
|
|
b94f99f338 | ||
|
|
bd21644571 | ||
|
|
5f3599d9b8 | ||
|
|
1e4a30bd70 | ||
|
|
e7dc5de9f2 | ||
|
|
ccb9cb28f5 | ||
|
|
4d9b72c922 | ||
|
|
a51ae13a39 | ||
|
|
dfca186688 | ||
|
|
fadd229a89 | ||
|
|
7acc69adc4 | ||
|
|
d88e4120a1 | ||
|
|
ef98edd91a | ||
|
|
f4548bbe34 | ||
|
|
11a5faca1d | ||
|
|
c37b0e8cb5 | ||
|
|
a20570a6eb | ||
|
|
5e3edb7e1d | ||
|
|
ad8f1d2da6 | ||
|
|
24b23c894f | ||
|
|
c551d5fb81 | ||
|
|
fba43894c1 | ||
|
|
22cc7e086c | ||
|
|
1791008729 | ||
|
|
90e15dd253 | ||
|
|
7db73c076c | ||
|
|
95ad6e99d9 | ||
|
|
0b2a5d0f61 | ||
|
|
b7acce0814 | ||
|
|
8744e76cad | ||
|
|
446b3c13dc | ||
|
|
3951e28148 | ||
|
|
b74d679608 | ||
|
|
edbc878b73 | ||
|
|
f706209ec1 | ||
|
|
bf000b188f | ||
|
|
def1736a9b | ||
|
|
0242f4c0c3 | ||
|
|
5cd399b2df | ||
|
|
9ddb662016 | ||
|
|
2947275d54 | ||
|
|
e43f814872 | ||
|
|
6e16f52e28 | ||
|
|
fca13557df | ||
|
|
824a6df55a | ||
|
|
b98b526c50 | ||
|
|
8f6aa4f4a5 | ||
|
|
00a07a79b2 | ||
|
|
264dfbef2e | ||
|
|
2e27814809 | ||
|
|
f767f40e56 | ||
|
|
543ecc071a | ||
|
|
2a14f39495 | ||
|
|
95c8ae2334 | ||
|
|
338ea13828 | ||
|
|
4a8b9e5fec | ||
|
|
e281cac3d3 | ||
|
|
a495829a3c | ||
|
|
b0deed2a89 | ||
|
|
70a75abf74 | ||
|
|
1aa97f8e79 | ||
|
|
b4000235ac | ||
|
|
4b93f29a1c | ||
|
|
4892a50670 | ||
|
|
2fe0ac0ef9 | ||
|
|
333ae72148 | ||
|
|
5fd5b7f303 | ||
|
|
528cf45f3f | ||
|
|
c7308e7320 | ||
|
|
e2a49eaab7 | ||
|
|
44bd6f235c | ||
|
|
601d15b513 | ||
|
|
9e93485a97 | ||
|
|
ad87b2115d | ||
|
|
27a587d31f | ||
|
|
fc8fa27602 | ||
|
|
f9aebc8ee3 | ||
|
|
1167da8f4c | ||
|
|
7a5fbcdccd | ||
|
|
345e929712 | ||
|
|
358862fe59 | ||
|
|
3dde9bb293 | ||
|
|
99ae4ccadd | ||
|
|
98e9ffe0ef | ||
|
|
6927bfe8ac | ||
|
|
340a3a8fa3 | ||
|
|
4724763991 | ||
|
|
03353ad08c | ||
|
|
95c3354fcd | ||
|
|
1bda2f92b9 | ||
|
|
bd3c706934 | ||
|
|
ef3663aa36 | ||
|
|
427ff717d4 | ||
|
|
b409300412 | ||
|
|
ca1f974dbe | ||
|
|
6a8c86096b | ||
|
|
2b2fd9965b | ||
|
|
0938635eb2 | ||
|
|
a4a186751e | ||
|
|
ea5169b5c5 | ||
|
|
01bd195847 | ||
|
|
a72c26a935 | ||
|
|
a9900d9bfa | ||
|
|
6896401d2d | ||
|
|
886f01c9f3 | ||
|
|
59c9251d70 | ||
|
|
fad5f010d2 | ||
|
|
737c4a92b9 | ||
|
|
d3e8675948 | ||
|
|
a4ffc7a27c | ||
|
|
91bf7b1387 | ||
|
|
1396296337 | ||
|
|
e4672355fc | ||
|
|
129ed25ca4 | ||
|
|
e6d7e5fe98 | ||
|
|
73ce5fa11f | ||
|
|
ce01c3d4ce | ||
|
|
3b3de316ea | ||
|
|
8c739ce54d | ||
|
|
0aa4d6c967 | ||
|
|
d7a3f4d87d | ||
|
|
fe9e074581 | ||
|
|
40813e8752 | ||
|
|
e90f2e4142 | ||
|
|
2a19ea709b | ||
|
|
30c9be303f | ||
|
|
e101b79472 | ||
|
|
8ad919f952 | ||
|
|
294543c46e | ||
|
|
79f8363d47 | ||
|
|
6d3553b0b5 | ||
|
|
403ab4e281 | ||
|
|
87e7c43032 | ||
|
|
a321b41699 | ||
|
|
fea34863e3 | ||
|
|
bcaf7ab73e | ||
|
|
b9d7eaee1b | ||
|
|
d605045858 | ||
|
|
cf2ab617c2 | ||
|
|
204514cb08 | ||
|
|
cfe01cca75 | ||
|
|
ac294c58ae | ||
|
|
6950eb2f30 | ||
|
|
847f81374b | ||
|
|
bb09aea8bb | ||
|
|
2e1ff333f5 | ||
|
|
c14a2b4011 | ||
|
|
d9c6c3d2d0 | ||
|
|
91d4477ed9 | ||
|
|
623c0a127e | ||
|
|
bc64666700 | ||
|
|
5c7dd7d782 | ||
|
|
e78a2da6c0 | ||
|
|
065be6f3d7 | ||
|
|
874f3330b8 | ||
|
|
684edfa10b | ||
|
|
e69a120965 | ||
|
|
4a36244294 | ||
|
|
cb444be0f7 | ||
|
|
8b5cbf186f | ||
|
|
dbc6f8a196 | ||
|
|
9b94604166 | ||
|
|
cc98a85711 | ||
|
|
6855d06f55 | ||
|
|
89d90ddf5b | ||
|
|
6280111121 | ||
|
|
231d41c15f | ||
|
|
cfca7adc66 | ||
|
|
aedd215de4 | ||
|
|
df8e839580 | ||
|
|
300441b9f7 | ||
|
|
1a5e9022ae | ||
|
|
2a3b8f87d3 | ||
|
|
b7930f1ed7 | ||
|
|
a78c2145e6 | ||
|
|
ee20a34a70 | ||
|
|
33bd80c572 | ||
|
|
031309b105 | ||
|
|
bcbd981a9b | ||
|
|
b7ce390c33 | ||
|
|
c9d099c694 | ||
|
|
fcca0329c6 | ||
|
|
c82c0bc680 | ||
|
|
2921478a0a | ||
|
|
61a5420d48 | ||
|
|
702ab6ef6e | ||
|
|
2576e71a7d | ||
|
|
0d0bd78213 | ||
|
|
8d9fa8f9cf | ||
|
|
25eaf6e353 | ||
|
|
8afcaa0b34 | ||
|
|
1824f8150c | ||
|
|
2f89778fd6 | ||
|
|
f9d250b43c | ||
|
|
3a3c09d8aa | ||
|
|
09a0d4f9e2 | ||
|
|
3bba781183 | ||
|
|
6426f8fe91 | ||
|
|
5906594148 | ||
|
|
1b188c863c | ||
|
|
087b4cb571 | ||
|
|
c9496b6231 | ||
|
|
60d95d7628 | ||
|
|
dd9e7e77b5 | ||
|
|
50c9363876 | ||
|
|
938e357745 | ||
|
|
08ee51f8ab | ||
|
|
40ae555645 | ||
|
|
33f89264a6 | ||
|
|
e4ea20cc5f | ||
|
|
045b7db1af | ||
|
|
676c1b5d21 | ||
|
|
e4319246b8 | ||
|
|
32d8515bf4 | ||
|
|
d7e7113201 | ||
|
|
9493aa43a7 | ||
|
|
d07c55b831 | ||
|
|
47dab88d72 | ||
|
|
9e553aeff6 | ||
|
|
ed8e754557 | ||
|
|
651dc3df2a | ||
|
|
84e5bc3437 | ||
|
|
64fd0176ac | ||
|
|
c1f3115d4e | ||
|
|
1c70834760 | ||
|
|
7c901731bc | ||
|
|
2b2d53e515 | ||
|
|
be051ecf45 | ||
|
|
18534eb654 | ||
|
|
a5a926fd94 | ||
|
|
0cb9f2cad3 | ||
|
|
98209cc82e | ||
|
|
1879afa6a4 | ||
|
|
4a6404dfec | ||
|
|
0fa1c4a08f | ||
|
|
573d7c5776 | ||
|
|
c56c9bf260 | ||
|
|
387865789f | ||
|
|
03fcf43a89 | ||
|
|
df8090813a | ||
|
|
849b29d00f | ||
|
|
4b7f65e1c4 | ||
|
|
4545d81e50 | ||
|
|
1ac5f060a4 | ||
|
|
7e1ff8e315 | ||
|
|
4e0c1fee97 | ||
|
|
0b38f23f2d | ||
|
|
98ea6861c1 | ||
|
|
c07b628ea1 | ||
|
|
b1b979c0b5 | ||
|
|
35b708b01d | ||
|
|
229ae0d44f | ||
|
|
7d6897fa36 | ||
|
|
5851093590 | ||
|
|
4646c1d1f0 | ||
|
|
f3763dbf72 | ||
|
|
6a8c60ec78 | ||
|
|
ae437fd5d6 | ||
|
|
7251c984c8 | ||
|
|
ec449220eb | ||
|
|
78265944f0 | ||
|
|
d2791f6d1b | ||
|
|
d525d2664b | ||
|
|
a4ccea91ad | ||
|
|
750da161eb | ||
|
|
ac50312f0b | ||
|
|
8d44d48072 | ||
|
|
6c2baa1708 | ||
|
|
4525cfe594 | ||
|
|
921f96c975 | ||
|
|
29ce57d3af | ||
|
|
2ca1e6305c | ||
|
|
827b404a57 | ||
|
|
83569142c1 | ||
|
|
2da0faacc3 | ||
|
|
cf51bee2cc | ||
|
|
0dd55dc947 | ||
|
|
620fa0430c | ||
|
|
d053590257 | ||
|
|
684af3de61 | ||
|
|
6c6e26ed0b | ||
|
|
4a05bfbd08 | ||
|
|
787dc7b32f | ||
|
|
85a1f99f6e | ||
|
|
4fe8a1199e | ||
|
|
7312dbc4c5 | ||
|
|
cfecfabc92 | ||
|
|
587160c5fe | ||
|
|
ee7fe3ed33 | ||
|
|
47d4a6cc29 | ||
|
|
c1e4763369 | ||
|
|
333ba0f162 | ||
|
|
e039b0e9f6 | ||
|
|
b3c5e3beca | ||
|
|
70ba45c3bd | ||
|
|
14ae44fcac | ||
|
|
f7618f5da4 | ||
|
|
d6c6e4c02e | ||
|
|
9365052b85 | ||
|
|
ef88063094 | ||
|
|
4cbaf85eea | ||
|
|
6c07123da3 | ||
|
|
04a4ce12c7 | ||
|
|
e00ed8ae37 | ||
|
|
218a79b60a | ||
|
|
19ae86c71f | ||
|
|
9250d4e64d | ||
|
|
9f5aa58a31 | ||
|
|
c8b0a88573 | ||
|
|
7cf3f49aa1 | ||
|
|
be2c803f82 | ||
|
|
fd1197e8dc | ||
|
|
115f91b64a | ||
|
|
dfb800473a | ||
|
|
c69c1bb134 | ||
|
|
5b501c7c2f | ||
|
|
8d5ce56ec2 | ||
|
|
15c97ddc18 | ||
|
|
36d7fbf4e9 | ||
|
|
919e7aa5c6 | ||
|
|
2174de2b71 | ||
|
|
cb9e914e44 | ||
|
|
15f856b762 | ||
|
|
991dba0d62 | ||
|
|
aa2685d6e4 | ||
|
|
0952150328 | ||
|
|
e6ef4d1546 | ||
|
|
16cf85abb9 | ||
|
|
5afe0ead94 | ||
|
|
b6c933f989 | ||
|
|
feaf1a1f06 | ||
|
|
6b54c6e886 | ||
|
|
a95b69ab79 | ||
|
|
a2492ae248 | ||
|
|
0db1c4413c | ||
|
|
8718bca6e8 | ||
|
|
6486863d00 | ||
|
|
bfc2397dbf | ||
|
|
0cfdb9795b | ||
|
|
d327757d59 | ||
|
|
e88c4fa2e3 | ||
|
|
69a0071e17 | ||
|
|
d3cfe809e7 | ||
|
|
0ca6e5401a | ||
|
|
8ff2b60ed4 | ||
|
|
1dbe125e27 | ||
|
|
32a595262d | ||
|
|
01431a93a4 | ||
|
|
00a12d8113 | ||
|
|
0f2474386c | ||
|
|
5de52ed6e8 | ||
|
|
099b3fb7f3 | ||
|
|
ed85e33403 | ||
|
|
daff7d095f | ||
|
|
a8ff82229f | ||
|
|
2874e7d195 | ||
|
|
8baea2657d | ||
|
|
03e9a5cbcb | ||
|
|
8d2f2a28af | ||
|
|
4a4bade180 | ||
|
|
28e72f9883 | ||
|
|
681e3967d2 | ||
|
|
640dcbc8d7 | ||
|
|
19276ecb91 | ||
|
|
9f9078cdc5 | ||
|
|
9bd1e0c97b | ||
|
|
c2c8f700a2 | ||
|
|
86895eb5ef | ||
|
|
e8dacd6b70 | ||
|
|
03fcf1dc95 | ||
|
|
953b2be224 | ||
|
|
55645ba2a0 | ||
|
|
858c6a0aaf | ||
|
|
85d4023fa2 | ||
|
|
607fc8e45f | ||
|
|
511a966ce5 | ||
|
|
6d135efbc6 | ||
|
|
5dff6310aa | ||
|
|
194a06c748 | ||
|
|
1ce97aa20d | ||
|
|
1c88fb0355 | ||
|
|
7b81c42377 | ||
|
|
1afa38a947 | ||
|
|
eedb418299 | ||
|
|
9efc14e627 | ||
|
|
0dc3d65307 | ||
|
|
e3ddbe609c | ||
|
|
f115934499 | ||
|
|
f5e290a47a | ||
|
|
29cd395888 | ||
|
|
9ca7855756 | ||
|
|
1f1ab112eb | ||
|
|
b172b66263 | ||
|
|
b08f9f5757 | ||
|
|
32e65ff304 | ||
|
|
40126c923e | ||
|
|
83ae5b0a13 | ||
|
|
aea6a2839d | ||
|
|
6211d9ff18 | ||
|
|
0e7fab71b8 | ||
|
|
a106c8ed60 | ||
|
|
ae52d0ab3d | ||
|
|
c993cd5b5a | ||
|
|
9bdd83cc6e | ||
|
|
1b6a23c1a9 | ||
|
|
2703d94b83 | ||
|
|
4cb51ecbe6 | ||
|
|
0cf64121ae | ||
|
|
58eb3c5d64 | ||
|
|
3c645b4c7f | ||
|
|
a540eed0ed | ||
|
|
ad567b4c40 | ||
|
|
6f8aeea870 | ||
|
|
87a1a7c641 | ||
|
|
178f96a3b5 | ||
|
|
cc629a1a7c | ||
|
|
1cb72df52e | ||
|
|
4c32422493 | ||
|
|
7361823ece | ||
|
|
03824a900c | ||
|
|
c40913d690 | ||
|
|
bdfdf153f7 | ||
|
|
fa9e62d2a7 | ||
|
|
bcca20dbbb | ||
|
|
bca42ee7b4 | ||
|
|
d5f2bae47c | ||
|
|
fe1e99c67c | ||
|
|
699d55d70e | ||
|
|
3d11a95a29 | ||
|
|
a983c53189 | ||
|
|
0ee28f59ce | ||
|
|
96ee0584b8 | ||
|
|
7352d5b8ed | ||
|
|
e79fdd887c | ||
|
|
7b5b0f34ff | ||
|
|
ae8fb992fb | ||
|
|
d5409518ed | ||
|
|
6bb2e152a5 | ||
|
|
c73ebf88db | ||
|
|
bfdceec81b | ||
|
|
dd444e3a0f | ||
|
|
79de8dbbca | ||
|
|
5c6f3c3712 | ||
|
|
0d0663a7de | ||
|
|
6d1c4e6c85 | ||
|
|
f539633497 | ||
|
|
d9ddd6d772 | ||
|
|
4a2ba4e914 | ||
|
|
cc864e3e69 | ||
|
|
4cd5bd37d3 | ||
|
|
ff14e675fa | ||
|
|
a46cb462a2 | ||
|
|
8077dedd03 | ||
|
|
6a707dff0c | ||
|
|
c9aa31d803 | ||
|
|
4494683db2 | ||
|
|
f440b2d639 | ||
|
|
324d4bd94e | ||
|
|
bb82d70f5a | ||
|
|
8d1022f70f | ||
|
|
00034981ef | ||
|
|
2b3b33979c | ||
|
|
8e0788ccf3 | ||
|
|
6e81541a3b | ||
|
|
6acb17da7c | ||
|
|
774286952b | ||
|
|
35a3c81391 | ||
|
|
90d28eb4f4 | ||
|
|
aab24fdbbe | ||
|
|
d0c24ed7a7 | ||
|
|
2260906396 | ||
|
|
0901195147 | ||
|
|
c11a8e7bd9 | ||
|
|
8176ec1b0a | ||
|
|
8f598fe4eb | ||
|
|
2fac5c853e | ||
|
|
4dbd6b57f8 | ||
|
|
a5f21a99d8 | ||
|
|
6f98b44471 | ||
|
|
b13b07fb05 | ||
|
|
1f8884a415 | ||
|
|
848a30b2db | ||
|
|
350ece1533 | ||
|
|
513183f55c | ||
|
|
b23434e3bb | ||
|
|
7084fb2ea2 | ||
|
|
5becdf4d50 | ||
|
|
5aa10e9d74 | ||
|
|
db462ec134 | ||
|
|
75e9f6162b | ||
|
|
970d530fbd | ||
|
|
13ffa2a3e5 | ||
|
|
8416826827 | ||
|
|
0a296ee857 | ||
|
|
bb45470078 | ||
|
|
d3c6ab8dc5 | ||
|
|
0bf34781c5 | ||
|
|
20940e82de | ||
|
|
78df572bec | ||
|
|
ffd0bec5c6 | ||
|
|
62783d0765 | ||
|
|
7116f33a3a | ||
|
|
a168dab8c0 | ||
|
|
e3e065f36e | ||
|
|
d282321d98 | ||
|
|
1abdb3b874 | ||
|
|
1807287321 | ||
|
|
a29652180b | ||
|
|
d4a85ac136 | ||
|
|
007f635081 | ||
|
|
f75e15a375 | ||
|
|
508c7c4c0a | ||
|
|
7166dc0ec0 | ||
|
|
1f28b7e803 | ||
|
|
5d77139965 | ||
|
|
126dab08b2 | ||
|
|
a8175d9e19 | ||
|
|
a5c11b5119 | ||
|
|
bfc6b04a30 | ||
|
|
a5dd878c66 | ||
|
|
ed7ce80565 | ||
|
|
e6b71a3975 | ||
|
|
ff5049edc9 | ||
|
|
a34218367b | ||
|
|
f712107fb8 | ||
|
|
fb3dd6049d | ||
|
|
13bd467152 | ||
|
|
d934f615ca | ||
|
|
5e5280a7fd | ||
|
|
be2a4d252f | ||
|
|
0392fd68a8 | ||
|
|
e642854e99 | ||
|
|
1a42292725 | ||
|
|
c523a761c5 | ||
|
|
a416ae564a | ||
|
|
ecd647ecc4 | ||
|
|
50d0096492 | ||
|
|
1a2d43479f | ||
|
|
2416e93004 | ||
|
|
db99445878 | ||
|
|
18459b71c2 | ||
|
|
16cbabc79d | ||
|
|
c470d31605 | ||
|
|
cdacc30633 | ||
|
|
e55d4d8a78 | ||
|
|
fcd3258a73 | ||
|
|
a8e9822381 | ||
|
|
dfdb37973f | ||
|
|
3f340a3f7e | ||
|
|
e64d522707 | ||
|
|
6c05a4a038 | ||
|
|
5c9279cca4 | ||
|
|
a4ae6dd9c4 | ||
|
|
ace4042649 | ||
|
|
76debd5c82 | ||
|
|
8c0db6db53 | ||
|
|
bc99f3f295 | ||
|
|
826aaf0128 | ||
|
|
754861e036 | ||
|
|
b1bbc50472 | ||
|
|
dcb6c6d3f8 | ||
|
|
3f608b91e9 | ||
|
|
9d488974a4 | ||
|
|
1fa834f559 | ||
|
|
812f83446e | ||
|
|
3497ab0c73 | ||
|
|
78de131f83 | ||
|
|
3a8ffa11fe | ||
|
|
dd62d82005 | ||
|
|
7b9c71dcda | ||
|
|
4a518f1309 | ||
|
|
3a0a717765 | ||
|
|
60bdf4d137 | ||
|
|
0ec329927a | ||
|
|
6a616b4652 | ||
|
|
0bf7ccd701 | ||
|
|
c924d936f3 | ||
|
|
ef1c437191 | ||
|
|
6e6d0529d6 | ||
|
|
2ab179568f | ||
|
|
dab56caa98 | ||
|
|
67afd13fbb | ||
|
|
3a26ddd539 | ||
|
|
5197d63c70 | ||
|
|
3d136b843e | ||
|
|
388b7fbba7 | ||
|
|
a833f20729 | ||
|
|
d3c63bf35a | ||
|
|
5a0eff2b67 | ||
|
|
e64a75cfab | ||
|
|
2d31b8521d | ||
|
|
60225e3f5f | ||
|
|
aeb7b38474 | ||
|
|
bfbcab4009 | ||
|
|
742c352080 | ||
|
|
643827354c | ||
|
|
2f7bebfc17 | ||
|
|
7bf8d60ddf | ||
|
|
09c51b6b4e | ||
|
|
84f6ce58a0 | ||
|
|
9e90ae5285 | ||
|
|
93b1c9f0d9 | ||
|
|
dab8ed8ceb | ||
|
|
f016e49111 | ||
|
|
b403f22284 | ||
|
|
ccb9ac93f7 | ||
|
|
72935f1ebe | ||
|
|
1f7d46219a | ||
|
|
9094f76de2 | ||
|
|
d67cbeb3f2 | ||
|
|
90562ebd04 | ||
|
|
b14e14659c | ||
|
|
84a15afc9a | ||
|
|
8c1aba5608 | ||
|
|
a72c689f07 | ||
|
|
1d74f34575 | ||
|
|
a24092d391 | ||
|
|
097ae701c1 | ||
|
|
e250a593a7 | ||
|
|
1547e6b714 | ||
|
|
9f14224269 | ||
|
|
ecc54f9bd5 | ||
|
|
521ee56d31 | ||
|
|
f9da063532 | ||
|
|
5070c27f6a | ||
|
|
c0664bb0a9 | ||
|
|
f8c92f1ec4 | ||
|
|
01930cfdc8 | ||
|
|
e76e321765 | ||
|
|
99d2db31f7 | ||
|
|
fa9015447b | ||
|
|
735ad0908b | ||
|
|
a080a6a8cc | ||
|
|
2cbc51cfdf | ||
|
|
8631b4bdf5 | ||
|
|
285cb86891 | ||
|
|
bf535a7161 | ||
|
|
34e37471b8 | ||
|
|
e223548b23 | ||
|
|
3a13d242f6 | ||
|
|
204e6ec99f | ||
|
|
7e348782e4 | ||
|
|
a4cbe7db17 | ||
|
|
f8101acb4b | ||
|
|
9ed2d59317 | ||
|
|
0329ad7832 | ||
|
|
53df45456f | ||
|
|
93698bacff | ||
|
|
9fbf63f720 | ||
|
|
b49c334f9f | ||
|
|
a374e1278b | ||
|
|
0a16fb85bd | ||
|
|
419d5bae09 | ||
|
|
d78f3565de | ||
|
|
4814e7db74 | ||
|
|
3470fd35d5 | ||
|
|
2915bae474 | ||
|
|
ae9be7ac25 | ||
|
|
4b9cb3716b | ||
|
|
38bd9fb204 | ||
|
|
433c0db4fb | ||
|
|
ccebc18b85 | ||
|
|
6fb85eb9ca | ||
|
|
c2dad0807f | ||
|
|
d6ba4a1ab7 | ||
|
|
f9fae91c71 | ||
|
|
fdb7ca29bc | ||
|
|
722ab55591 | ||
|
|
450b390ac4 | ||
|
|
39eca5d39e | ||
|
|
4a4b9ad1d2 | ||
|
|
ea01647200 | ||
|
|
1f8faa8afd | ||
|
|
2b78d145ea | ||
|
|
e69b8bcd64 | ||
|
|
3dcd85e902 | ||
|
|
deab165c7f | ||
|
|
e405c4dc15 | ||
|
|
c5260584fa | ||
|
|
15cd16e771 | ||
|
|
11d8d36c12 | ||
|
|
d542ac9110 | ||
|
|
3d0e4ee7d7 | ||
|
|
379a399d29 | ||
|
|
26f0324573 | ||
|
|
a71f1a17dd | ||
|
|
9f4f459ea8 | ||
|
|
adafb9645c | ||
|
|
09c825bbcd | ||
|
|
255c1d945c | ||
|
|
c5eb49d12c | ||
|
|
ad690724a6 | ||
|
|
1573e79041 | ||
|
|
4d8026ec99 | ||
|
|
5c1c2b18e4 | ||
|
|
66baca51d7 | ||
|
|
355441e795 | ||
|
|
902fd70eb4 | ||
|
|
4ce7eee4aa | ||
|
|
6a73c2a697 | ||
|
|
f713669d1f | ||
|
|
d5365af373 | ||
|
|
ccffa0d5c2 | ||
|
|
0ee5b911d2 | ||
|
|
c92d17abbc | ||
|
|
ef5ef4ed72 | ||
|
|
ba5f4a24c7 | ||
|
|
1cd5fe0b02 | ||
|
|
21af487aab | ||
|
|
f254519a1c | ||
|
|
26fc039aa5 | ||
|
|
7d3e4529af | ||
|
|
bcefaee3e9 | ||
|
|
3933eaa1cf | ||
|
|
28251435e4 | ||
|
|
d29dc320c3 | ||
|
|
d14a939acb | ||
|
|
e20619e0c9 | ||
|
|
8ff829f1b1 | ||
|
|
402255ba0d | ||
|
|
7250bf8047 | ||
|
|
c76436cd3c | ||
|
|
9b85562595 | ||
|
|
4798ddfe19 | ||
|
|
dd197cfa24 | ||
|
|
844b9c19e5 | ||
|
|
5f6f1ebc44 | ||
|
|
71b91e6896 | ||
|
|
30d4296687 | ||
|
|
7b0a576b00 | ||
|
|
808a3c2e9c | ||
|
|
c700ffbadc | ||
|
|
e2057676bd | ||
|
|
f7dfb32849 | ||
|
|
6413161dc8 | ||
|
|
46a89d9847 | ||
|
|
d83d6b5671 | ||
|
|
b1abe91bd2 | ||
|
|
bf4138178b | ||
|
|
5b99084616 | ||
|
|
b95064b87e | ||
|
|
e1eece34b7 | ||
|
|
19d6a06bfa | ||
|
|
2fd13d1481 | ||
|
|
23a0a80e3a | ||
|
|
bb493d43b5 | ||
|
|
ef9eaa0a66 | ||
|
|
1d640f943a | ||
|
|
84f5f065ad | ||
|
|
921aedaf9d | ||
|
|
0f545923b2 | ||
|
|
5b32a91874 | ||
|
|
25b2528416 | ||
|
|
d29c95c38f | ||
|
|
a661ab2ff5 | ||
|
|
ac08ebee75 | ||
|
|
8e1a287ed1 | ||
|
|
9b656b3970 | ||
|
|
a1c0bbf413 | ||
|
|
2ad8c5d425 | ||
|
|
75aaa980cf | ||
|
|
7c55326d23 | ||
|
|
aa3ade5912 | ||
|
|
c692deebe9 | ||
|
|
9ff161c97d | ||
|
|
5b1f820621 | ||
|
|
30b2cffcb8 | ||
|
|
709439bfca | ||
|
|
34adb238f7 | ||
|
|
76c54f8d54 | ||
|
|
6196c05f12 | ||
|
|
37df0af56c | ||
|
|
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 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@
|
|||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
|
/target/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<h1>项目介绍</h1>
|
<h1>项目介绍</h1>
|
||||||
<p>
|
<p>
|
||||||
Redkale (中文名: 红菜苔,湖北武汉的一种特产蔬菜) 是基于Java 8全新的微服务框架, 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
|
Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 11全新的微服务框架, 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
|
||||||
</p>
|
</p>
|
||||||
<strong>RedKale 有如下主要特点:</strong>
|
<strong>RedKale 有如下主要特点:</strong>
|
||||||
<ol>
|
<ol>
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
由于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>
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,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 -DCMD=APIDOC -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
|
java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
7
bin/command.bat
Normal file
7
bin/command.bat
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
SET APP_HOME=%~dp0
|
||||||
|
|
||||||
|
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
|
||||||
|
|
||||||
|
java -DCMD=%1 -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application
|
||||||
23
bin/command.sh
Normal file
23
bin/command.sh
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export LC_ALL="zh_CN.UTF-8"
|
||||||
|
|
||||||
|
APP_HOME=`dirname "$0"`
|
||||||
|
|
||||||
|
cd "$APP_HOME"/..
|
||||||
|
|
||||||
|
APP_HOME=`pwd`
|
||||||
|
|
||||||
|
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
|
||||||
|
APP_HOME="$APP_HOME"/..
|
||||||
|
fi
|
||||||
|
|
||||||
|
lib="$APP_HOME"/lib
|
||||||
|
for jar in `ls $APP_HOME/lib/*.jar`
|
||||||
|
do
|
||||||
|
lib=$lib:$jar
|
||||||
|
done
|
||||||
|
export CLASSPATH=$CLASSPATH:$lib
|
||||||
|
|
||||||
|
echo "$APP_HOME"
|
||||||
|
java -DCMD=$1 -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
|
||||||
9
bin/restart.bat
Normal file
9
bin/restart.bat
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
SET APP_HOME=%~dp0
|
||||||
|
|
||||||
|
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
|
||||||
|
|
||||||
|
call "%APP_HOME%\bin\shutdown.bat"
|
||||||
|
|
||||||
|
call "%APP_HOME%\bin\start.bat"
|
||||||
20
bin/restart.sh
Normal file
20
bin/restart.sh
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export LC_ALL="zh_CN.UTF-8"
|
||||||
|
|
||||||
|
APP_HOME=`dirname "$0"`
|
||||||
|
|
||||||
|
cd "$APP_HOME"/..
|
||||||
|
|
||||||
|
APP_HOME=`pwd`
|
||||||
|
|
||||||
|
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
|
||||||
|
APP_HOME="$APP_HOME"/..
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$APP_HOME"
|
||||||
|
|
||||||
|
"$APP_HOME"/bin/shutdown.sh
|
||||||
|
|
||||||
|
"$APP_HOME"/bin/start.sh
|
||||||
|
|
||||||
@@ -4,4 +4,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 -DCMD=SHUTDOWN -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
|
java -DCMD=SHUTDOWN -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ 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 -server -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
|
||||||
|
|
||||||
@@ -20,5 +24,5 @@ done
|
|||||||
export CLASSPATH=$CLASSPATH:$lib
|
export CLASSPATH=$CLASSPATH:$lib
|
||||||
|
|
||||||
echo "$APP_HOME"
|
echo "$APP_HOME"
|
||||||
nohup java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application > "$APP_HOME"/log.out &
|
nohup java -server -DAPP_HOME="$APP_HOME" org.redkale.boot.Application > "$APP_HOME"/logs.out &
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,31 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<application port="5050">
|
<application nodeid="10000" port="2020">
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<!--
|
|
||||||
<properties>
|
|
||||||
<property name="system.property.convert.json.tiny" value="true"/>
|
|
||||||
</properties>
|
|
||||||
-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
|
<server protocol="HTTP" port="5050">
|
||||||
<!--
|
|
||||||
<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" />
|
||||||
<rewrite type="location" match="^/([^-]+)(-[^-\.]+)+\.html(.*)" forward="/$1.html"/>
|
|
||||||
</resource-servlet>
|
<servlets path="/pipes" autoload="true" />
|
||||||
-->
|
|
||||||
</servlets>
|
|
||||||
</server>
|
</server>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
handlers = java.util.logging.ConsoleHandler
|
handlers = java.util.logging.ConsoleHandler
|
||||||
|
# handlers = java.util.logging.FileHandler
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
.level = FINE
|
.level = FINEST
|
||||||
|
|
||||||
java.level = INFO
|
java.level = INFO
|
||||||
javax.level = INFO
|
javax.level = INFO
|
||||||
@@ -12,12 +13,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 = 10M
|
||||||
java.util.logging.FileHandler.count = 10000
|
java.util.logging.FileHandler.count = 20
|
||||||
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 = FINEST
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<persistence version="2.0">
|
||||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
|
||||||
|
|
||||||
<persistence-unit name="" transaction-type="RESOURCE_LOCAL">
|
<persistence-unit name="" 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/center?autoReconnect=true&characterEncoding=utf8"/>
|
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?autoReconnect=true&characterEncoding=utf8"/>
|
||||||
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
|
||||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||||
<property name="javax.persistence.jdbc.password" value="1234"/>
|
<property name="javax.persistence.jdbc.password" value="1234"/>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -16,9 +14,8 @@
|
|||||||
<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.user" value="system"/>
|
||||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
|
||||||
<property name="javax.persistence.jdbc.password" value="1234"/>
|
<property name="javax.persistence.jdbc.password" value="1234"/>
|
||||||
</properties>
|
</properties>
|
||||||
</persistence-unit>
|
</persistence-unit>
|
||||||
@@ -26,8 +23,7 @@
|
|||||||
<persistence-unit name="user.write" transaction-type="RESOURCE_LOCAL">
|
<persistence-unit name="user.write" 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:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"/>
|
||||||
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
|
||||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||||
<property name="javax.persistence.jdbc.password" value="1234"/>
|
<property name="javax.persistence.jdbc.password" value="1234"/>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@@ -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>
|
||||||
32
my/assembly.xml
Normal file
32
my/assembly.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||||
|
<id>redkale</id>
|
||||||
|
<formats>
|
||||||
|
<format>tar.gz</format>
|
||||||
|
</formats>
|
||||||
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/bin</directory>
|
||||||
|
<outputDirectory>bin</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/conf</directory>
|
||||||
|
<outputDirectory>conf</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/logs</directory>
|
||||||
|
<outputDirectory>logs</outputDirectory>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
<dependencySets>
|
||||||
|
<dependencySet>
|
||||||
|
<useProjectArtifact>true</useProjectArtifact>
|
||||||
|
<useTransitiveDependencies>false</useTransitiveDependencies>
|
||||||
|
<outputDirectory>lib</outputDirectory>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependencySet>
|
||||||
|
</dependencySets>
|
||||||
|
</assembly>
|
||||||
166
my/pom.xml
Normal file
166
my/pom.xml
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.redkale</groupId>
|
||||||
|
<artifactId>redkale</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>RedkaleProject</name>
|
||||||
|
<url>http://redkale.org</url>
|
||||||
|
<description>redkale -- java framework</description>
|
||||||
|
<version>2.5.0</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>5.7.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache 2</name>
|
||||||
|
<url>https://www.apache.org/licenses/</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
<comments>Apache License</comments>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>Redkale</id>
|
||||||
|
<name>redkale</name>
|
||||||
|
<email>redkale@qq.com</email>
|
||||||
|
<url>https://redkale.org</url>
|
||||||
|
<roles>
|
||||||
|
<role>Project Manager</role>
|
||||||
|
<role>Architect</role>
|
||||||
|
</roles>
|
||||||
|
<organization>redkale</organization>
|
||||||
|
<organizationUrl>https://redkale.org</organizationUrl>
|
||||||
|
<properties>
|
||||||
|
<dept>No</dept>
|
||||||
|
</properties>
|
||||||
|
<timezone>8</timezone>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
<repository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<url>https://github.com/redkale/redkale</url>
|
||||||
|
<connection>scm:git:git@github.com/redkale/redkale.git</connection>
|
||||||
|
<developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<configuration>
|
||||||
|
<compilerArgument>-parameters</compilerArgument>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<compilerArguments>
|
||||||
|
<verbose />
|
||||||
|
</compilerArguments>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<addMavenDescriptor>false</addMavenDescriptor>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>org.redkale.boot.Application</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
<version>1.6</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>sign-artifacts</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>sign</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>assembly.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>redkale</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
1
my/readme.txt
Normal file
1
my/readme.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD>Ŀ¼<EFBFBD>µ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatypeʱʹ<EFBFBD>ã<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9>̴<EFBFBD><CCB4><EFBFBD><EFBFBD><EFBFBD>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<profile>
|
<profile>
|
||||||
<id>release</id>
|
<id>release</id>
|
||||||
|
<!--
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@@ -92,6 +93,7 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
-->
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
</settings>
|
</settings>
|
||||||
154
pom.xml
154
pom.xml
@@ -4,30 +4,66 @@
|
|||||||
<groupId>org.redkale</groupId>
|
<groupId>org.redkale</groupId>
|
||||||
<artifactId>redkale</artifactId>
|
<artifactId>redkale</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<url>http://redkale.org</url>
|
<name>RedkaleProject</name>
|
||||||
|
<url>https://redkale.org</url>
|
||||||
<description>redkale -- java framework</description>
|
<description>redkale -- java framework</description>
|
||||||
<version>1.4.0-SNAPSHOT</version>
|
<version>2.5.0</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
|
||||||
|
<junit.version>5.7.0</junit.version>
|
||||||
|
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
|
||||||
|
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||||
|
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
||||||
|
<maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>Apache 2</name>
|
<name>Apache 2</name>
|
||||||
<url>http://www.apache.org/licenses/</url>
|
<url>https://www.apache.org/licenses/</url>
|
||||||
<distribution>repo</distribution>
|
<distribution>repo</distribution>
|
||||||
<comments>Apache License</comments>
|
<comments>Apache License</comments>
|
||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>central</id>
|
||||||
|
<name>Central Repository</name>
|
||||||
|
<url>https://repo.maven.apache.org/maven2</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>sonatype-nexus-snapshots</id>
|
||||||
|
<name>Sonatype Nexus Snapshots</name>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
<developer>
|
<developer>
|
||||||
<id>Redkale</id>
|
<id>Redkale</id>
|
||||||
<name>redkale</name>
|
<name>redkale</name>
|
||||||
<email>redkale@qq.com</email>
|
<email>redkale@qq.com</email>
|
||||||
<url>http://redkale.org</url>
|
<url>https://redkale.org</url>
|
||||||
<roles>
|
<roles>
|
||||||
<role>Project Manager</role>
|
<role>Project Manager</role>
|
||||||
<role>Architect</role>
|
<role>Architect</role>
|
||||||
</roles>
|
</roles>
|
||||||
<organization>redkale</organization>
|
<organization>redkale</organization>
|
||||||
<organizationUrl>http://redkale.org</organizationUrl>
|
<organizationUrl>https://redkale.org</organizationUrl>
|
||||||
<properties>
|
<properties>
|
||||||
<dept>No</dept>
|
<dept>No</dept>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -35,48 +71,49 @@
|
|||||||
</developer>
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
|
||||||
</properties>
|
|
||||||
<name>Redkale</name>
|
|
||||||
<distributionManagement>
|
|
||||||
<snapshotRepository>
|
|
||||||
<id>ossrh</id>
|
|
||||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
|
||||||
</snapshotRepository>
|
|
||||||
<repository>
|
|
||||||
<id>ossrh</id>
|
|
||||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
|
||||||
</repository>
|
|
||||||
</distributionManagement>
|
|
||||||
<scm>
|
<scm>
|
||||||
<url>https://github.com/redkale/redkale</url>
|
<url>https://github.com/redkale/redkale</url>
|
||||||
<connection>scm:git:git@github.com/redkale/redkale.git</connection>
|
<connection>scm:git:git@github.com/redkale/redkale.git</connection>
|
||||||
<developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection>
|
<developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.5.1</version>
|
|
||||||
<configuration>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
<compilerArguments>
|
|
||||||
<verbose />
|
|
||||||
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
|
|
||||||
</compilerArguments>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>${maven-compiler-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<compilerArgs>
|
||||||
|
<arg>-parameters</arg>
|
||||||
|
</compilerArgs>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- 需要注释掉, 否则会生成native-image配置信息
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.redkale.maven.plugins</groupId>
|
||||||
|
<artifactId>redkale-maven-plugin</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>redkale-compile</id>
|
||||||
|
<phase>process-classes</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
-->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.6</version>
|
<version>${maven-jar-plugin.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
|
<addMavenDescriptor>false</addMavenDescriptor>
|
||||||
<manifest>
|
<manifest>
|
||||||
<mainClass>org.redkale.boot.Application</mainClass>
|
<mainClass>org.redkale.boot.Application</mainClass>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -86,55 +123,16 @@
|
|||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>1.6</version>
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>sign-artifacts</id>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>sign</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>${maven-failsafe-plugin.version}</version>
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.10.3</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</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>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
文件说明:
|
|
||||||
${APP_HOME} 指当前程序的根目录APP_HOME
|
|
||||||
没注明唯一的节点可多个存在
|
|
||||||
required: 被声明required的属性值不能为空
|
|
||||||
|
|
||||||
group
|
|
||||||
/ / \ \
|
|
||||||
/ / \ \
|
|
||||||
/ / \ \
|
|
||||||
node1 node2 node3 node4
|
|
||||||
/ \
|
|
||||||
/ \
|
|
||||||
/ \
|
|
||||||
/ \
|
|
||||||
serviceid1 serviceid2
|
|
||||||
/ \ / \
|
|
||||||
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
|
|
||||||
-->
|
|
||||||
<!--
|
|
||||||
address: 本地局域网的IP地址, 默认值为默认网卡的ip,当不使用默认值需要指定值,如192.168.1.22
|
|
||||||
port: required 程序的管理Server的端口,用于关闭或者与监管系统进行数据交互
|
|
||||||
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
|
|
||||||
-->
|
|
||||||
<application port="6560" lib="">
|
|
||||||
|
|
||||||
<!--
|
|
||||||
【节点全局唯一】
|
|
||||||
所有服务所需的资源
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<!--
|
|
||||||
【节点全局唯一】
|
|
||||||
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
|
||||||
threads: 线程总数, 默认: <group>节点数*CPU核数*8
|
|
||||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 8K;
|
|
||||||
bufferPoolSize: ByteBuffer池的大小,默认: <group>节点数*CPU核数*8
|
|
||||||
-->
|
|
||||||
<transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/>
|
|
||||||
<!--
|
|
||||||
一个组包含多个NODE, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
|
||||||
一个group节点对应一个 Transport 对象。
|
|
||||||
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
|
||||||
protocol:值范围:UDP TCP, 默认TCP
|
|
||||||
subprotocol: 子协议,预留字段。默认值为空
|
|
||||||
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
|
||||||
-->
|
|
||||||
<group name="" protocol="TCP">
|
|
||||||
<!--
|
|
||||||
需要将本地node的addr与port列在此处。
|
|
||||||
同一个<node>节点值只能存在一个<group>节点内,即同一个addr+port只能属于一个group。
|
|
||||||
addr: required IP地址
|
|
||||||
port: required 端口
|
|
||||||
clients: 连接池数, 默认: CPU核数*4
|
|
||||||
buffers: ByteBuffer对象池的大小, 默认: CPU核数*8
|
|
||||||
-->
|
|
||||||
<node addr="127.0.0.1" port="7070"/>
|
|
||||||
</group>
|
|
||||||
<!--
|
|
||||||
【节点全局唯一】
|
|
||||||
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
|
|
||||||
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
|
||||||
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
|
||||||
load: 加载文件,多个用;隔开。
|
|
||||||
默认置入的system.property.的有:
|
|
||||||
System.setProperty("convert.json.tiny", "true");
|
|
||||||
System.setProperty("convert.bson.tiny", "true");
|
|
||||||
System.setProperty("convert.json.pool.size", "128");
|
|
||||||
System.setProperty("convert.bson.pool.size", "128");
|
|
||||||
System.setProperty("convert.json.writer.buffer.defsize", "4096");
|
|
||||||
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
|
|
||||||
|
|
||||||
<properties>节点下也可包含非<property>节点,其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
|
|
||||||
-->
|
|
||||||
<properties load="config.properties">
|
|
||||||
<property name="system.property.yyyy" value="YYYYYY"/>
|
|
||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
|
||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
|
||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
<!--
|
|
||||||
protocol: required server所启动的协议,Redkale内置的有HTTP、SNCP,SNCP使用TCP实现;
|
|
||||||
name: 服务的名称,用于监控识别,一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线、减号
|
|
||||||
host: 服务所占address , 默认: 0.0.0.0
|
|
||||||
port: required 服务所占端口
|
|
||||||
root: 如果是web类型服务,则包含页面 默认:{APP_HOME}/root
|
|
||||||
lib: server额外的class目录, 默认为空
|
|
||||||
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
|
||||||
charset: 文本编码, 默认: UTF-8
|
|
||||||
backlog: 默认10K
|
|
||||||
threads: 线程总数, 默认: CPU核数*16
|
|
||||||
maxbody: request.body最大值, 默认: 64K
|
|
||||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 8K; 如果是HTTP协议则默认: 16K + 8B (兼容HTTP 2.0)
|
|
||||||
bufferPoolSize: ByteBuffer池的大小,默认: CPU核数*512
|
|
||||||
responsePoolSize: Response池的大小,默认: CPU核数*256
|
|
||||||
readTimeoutSecond: 读操作超时秒数, 默认0, 表示永久不超时
|
|
||||||
writeTimeoutSecond: 写操作超时秒数, 默认0, 表示永久不超时
|
|
||||||
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类,必须是org.redkale.boot.NodeInterceptor的子类,默认为null
|
|
||||||
-->
|
|
||||||
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
|
|
||||||
|
|
||||||
<!--
|
|
||||||
加载所有的Service服务;
|
|
||||||
在同一个进程中同一个name同一类型的Service将共用同一个实例
|
|
||||||
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Service类:
|
|
||||||
server.lib; server.lib/*; server.classes;
|
|
||||||
autoload="false" 需要显著的指定Service类
|
|
||||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
|
||||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
|
||||||
groups: 所属组的节点,多个节点值用;隔开,如果配置文件中存在多个SNCP协议的Server节点,需要显式指定group属性.
|
|
||||||
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
|
|
||||||
当 protocol != SNCP 时 group只能是空或者一个group的节点值,不能为多个节点值。
|
|
||||||
-->
|
|
||||||
<services autoload="true" includes="" excludes="">
|
|
||||||
|
|
||||||
<!-- 显著加载指定的Service的接口类 -->
|
|
||||||
<service value="com.xxx.XXX1Service"/>
|
|
||||||
<!--
|
|
||||||
name: 显式指定name,覆盖默认的空字符串值。 注意: name不能包含$符号。
|
|
||||||
groups: 显式指定groups,覆盖<services>节点的groups默认值。
|
|
||||||
-->
|
|
||||||
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
|
|
||||||
<!-- 给Service增加配置属性 -->
|
|
||||||
<service value="com.xxx.XXX1Service">
|
|
||||||
<!-- property节点值在 public void init(AnyValue conf) 方法中可以通过 AnyValue properties = conf.getAnyValue("properties");获取 -->
|
|
||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
|
||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
|
||||||
</service>
|
|
||||||
</services>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
REST的核心配置项
|
|
||||||
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个
|
|
||||||
base: REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
|
|
||||||
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
|
|
||||||
mustsign:默认值"true" 是否只加载标记为RestService的Service类,默认只加载标记RestService且ignore=false的Service
|
|
||||||
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
|
||||||
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
|
||||||
-->
|
|
||||||
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes="">
|
|
||||||
<!--
|
|
||||||
value: Service类名,列出的表示必须被加载的Service对象
|
|
||||||
ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
|
|
||||||
-->
|
|
||||||
<service value="com.xxx.XXXXService"/>
|
|
||||||
</rest>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
【节点在<server>中唯一】
|
|
||||||
当Server为HTTP协议时, request节点才有效。
|
|
||||||
remoteaddr 节点: 替换请求方节点的IP地址, 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。
|
|
||||||
且value值只能是以request.headers.开头,表示从request.headers中获取对应的header值。
|
|
||||||
例如下面例子获取request.getRemoteAddr()值,如果header存在X-RemoteAddress值则返回X-RemoteAddress值,不存在返回getRemoteAddress()。
|
|
||||||
-->
|
|
||||||
<request>
|
|
||||||
<remoteaddr value="request.headers.X-RemoteAddress"/>
|
|
||||||
</request>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
【节点在<server>中唯一】
|
|
||||||
当Server为HTTP协议时, response节点才有效。
|
|
||||||
defcookie 节点: 当response里输出的cookie没有指定domain 和path时,使用该节点的默认值。
|
|
||||||
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
|
|
||||||
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
|
|
||||||
例如下面例子是在Response输出header时添加两个header(一个addHeader, 一个setHeader)。
|
|
||||||
-->
|
|
||||||
<response>
|
|
||||||
<defcookie domain="" path=""/>
|
|
||||||
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
|
||||||
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
|
||||||
</response>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
【节点在<server>中唯一】
|
|
||||||
当Server为HTTP协议时,ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
|
|
||||||
webroot: web资源的根目录, 默认取server节点中的root值
|
|
||||||
servlet: 静态资源HttpServlet的实现,默认使用HttpResourceServlet
|
|
||||||
index : 启始页,默认值:index.html
|
|
||||||
-->
|
|
||||||
<resource-servlet webroot="root" index="index.html">
|
|
||||||
<!--
|
|
||||||
【节点在<resource-servlet>中唯一】
|
|
||||||
资源缓存的配置, 默认存在一个含默认属性的caches节点
|
|
||||||
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存, 单位可以是B、K、M、G,不区分大小写
|
|
||||||
lengthmax: 可缓存的文件大小上限, 默认: 1M(超过1M的文件不会被缓存)
|
|
||||||
watch: 是否监控缓存文件的变化, 默认为false,不监控
|
|
||||||
-->
|
|
||||||
<cache limit="0M" lengthmax="1M" watch="false"/>
|
|
||||||
<!--
|
|
||||||
支持类似nginx中的rewrite, 目前只支持静态资源对静态资源的跳转。
|
|
||||||
type: 匹配的类型, 目前只支持location(匹配requestURI), 默认: location
|
|
||||||
match: 匹配的正则表达式
|
|
||||||
forward: 需跳转后的资源链接
|
|
||||||
例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html
|
|
||||||
-->
|
|
||||||
<rewrite type="location" match="^/([^-]+)-[^-\.]+\.html(.*)" forward="/$1.html"/>
|
|
||||||
</resource-servlet>
|
|
||||||
<!--
|
|
||||||
加载所有的Servlet服务;
|
|
||||||
path: servlet的ContextPath前缀 默认为空
|
|
||||||
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Servlet类:
|
|
||||||
${APP_HOME}/lib; ${APP_HOME}/root/lib/*; ${APP_HOME}/root/classes;
|
|
||||||
autoload="false" 需要显著的指定Service类
|
|
||||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
|
||||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
|
||||||
-->
|
|
||||||
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
|
||||||
<!-- 显著加载指定的Servlet -->
|
|
||||||
<servlet value="com.xxx.XXX1Servlet" />
|
|
||||||
<servlet value="com.xxx.XXX2Servlet" />
|
|
||||||
<servlet value="com.xxx.XXX3Servlet" >
|
|
||||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
|
||||||
<property name="yyyyyy" value="YYYYYYYY"/>
|
|
||||||
</servlet>
|
|
||||||
</servlets>
|
|
||||||
</server>
|
|
||||||
|
|
||||||
<server protocol="SNCP" host="127.0.0.1" port="7070" root="root" lib="">
|
|
||||||
<!-- 参数完全同上 -->
|
|
||||||
<services autoload="true" includes="" excludes="" />
|
|
||||||
</server>
|
|
||||||
</application>
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/** *****************************************************************************
|
|
||||||
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
|
|
||||||
* which accompanies this distribution.
|
|
||||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
* and the Eclipse Distribution License is available at
|
|
||||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Linda DeMichiel - Java Persistence 2.1
|
|
||||||
* Linda DeMichiel - Java Persistence 2.0
|
|
||||||
*
|
|
||||||
***************************************************************************** */
|
|
||||||
package javax.persistence;
|
|
||||||
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import static java.lang.annotation.ElementType.FIELD;
|
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides for the specification of generation strategies for the
|
|
||||||
* values of primary keys.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The <code>GeneratedValue</code> annotation
|
|
||||||
* may be applied to a primary key property or field of an entity or
|
|
||||||
* mapped superclass in conjunction with the {@link Id} annotation.
|
|
||||||
* The use of the <code>GeneratedValue</code> annotation is only
|
|
||||||
* required to be supported for simple primary keys. Use of the
|
|
||||||
* <code>GeneratedValue</code> annotation is not supported for derived
|
|
||||||
* primary keys.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
*
|
|
||||||
* Example 1:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* public Long getId() { return id; }
|
|
||||||
*
|
|
||||||
* Example 2:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* Long id;
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see Id
|
|
||||||
*
|
|
||||||
* @since Java Persistence 1.0
|
|
||||||
*/
|
|
||||||
@Target({METHOD, FIELD})
|
|
||||||
@Retention(RUNTIME)
|
|
||||||
|
|
||||||
public @interface GeneratedValue {
|
|
||||||
|
|
||||||
}
|
|
||||||
374
src/main/java/META-INF/application-template.xml
Normal file
374
src/main/java/META-INF/application-template.xml
Normal file
@@ -0,0 +1,374 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
文件说明:
|
||||||
|
${APP_HOME} 指当前程序的根目录APP_HOME
|
||||||
|
没注明唯一的节点可多个存在
|
||||||
|
required: 被声明required的属性值不能为空
|
||||||
|
|
||||||
|
group
|
||||||
|
/ / \ \
|
||||||
|
/ / \ \
|
||||||
|
/ / \ \
|
||||||
|
node1 node2 node3 node4
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
serviceid1 serviceid2
|
||||||
|
/ \ / \
|
||||||
|
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
nodeid: int 进程的节点ID,用于分布式环境,一个系统中节点ID必须全局唯一,使用cluster时框架会进行唯一性校验
|
||||||
|
name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线
|
||||||
|
address: 本地局域网的IP地址, 默认值为默认网卡的ip,当不使用默认值需要指定值,如192.168.1.22
|
||||||
|
port: required 程序的管理Server的端口,用于关闭或者与监管系统进行数据交互
|
||||||
|
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
|
||||||
|
-->
|
||||||
|
<application nodeid="1000" port="6560" lib="">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点全局唯一】
|
||||||
|
所有服务所需的资源
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点全局唯一】 @since 2.3.0
|
||||||
|
全局Serivce执行的线程池, Application.workExecutor, 没配置该节点将自动创建一个。
|
||||||
|
threads: 线程数,为0表示不启用workExecutor,只用IO线程。默认: CPU核数, 核数=1的情况下默认值为2
|
||||||
|
hash: 是否使用ThreadHashExecutor作为线程池,默认值为:false
|
||||||
|
-->
|
||||||
|
<executor threads="4" hash="false"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点全局唯一】
|
||||||
|
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
||||||
|
threads: 线程总数, 默认: <group>节点数*CPU核数*2
|
||||||
|
bufferCapacity: ByteBuffer的初始化大小, 默认: 32K;
|
||||||
|
bufferPoolSize: ByteBuffer池的大小,默认: 线程总数*4
|
||||||
|
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒, 为0表示无超时限制
|
||||||
|
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒, 为0表示无超时限制
|
||||||
|
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
|
||||||
|
-->
|
||||||
|
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSeconds="6" writeTimeoutSeconds="6"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点全局唯一】
|
||||||
|
自动扫描时排除部分包路径
|
||||||
|
value: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||||
|
-->
|
||||||
|
<excludelibs value="^.*mysql.*$;^.*kafka.*$"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点全局唯一】
|
||||||
|
第三方服务发现管理接口
|
||||||
|
value: 类名,必须是org.redkale.cluster.ClusterAgent的子类
|
||||||
|
waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁,默认值为:false
|
||||||
|
当一个Service进行服务注销后,不能立刻销毁Service,因为健康检测是有间隔时间差的,
|
||||||
|
需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
|
||||||
|
如果使用MQ,可以设置为false,如果对服务健壮性要求高,建议设置为true
|
||||||
|
protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
|
||||||
|
ports: 服务发现可以处理的端口, 多个端口用分号;隔开
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
<cluster value="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071">
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
</cluster>
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
MQ管理接口配置
|
||||||
|
不同MQ节点所配置的MQ集群不能重复。
|
||||||
|
MQ跟着协议走,所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的,故SNCP协议下,mq属性值被赋值在service/services节点上
|
||||||
|
name: 服务的名称,用于监控识别,多个mq节点时只能有一个name为空的节点,mq.name不能重复,命名规则: 字母、数字、下划线
|
||||||
|
value: 实现类名,必须是org.redkale.mq.MessageAgent的子类
|
||||||
|
MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
<mq name="" value="org.redkalex.mq.kafka.KafkaMessageAgent">
|
||||||
|
<servers value="127.0.0.1:9101"/>
|
||||||
|
<consumer>
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
</consumer>
|
||||||
|
<producer>
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
</producer>
|
||||||
|
</mq>
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
一个组包含多个node, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
||||||
|
一个group节点对应一个 Transport 对象。
|
||||||
|
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
||||||
|
protocol: 值范围:UDP TCP, 默认TCP
|
||||||
|
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
||||||
|
-->
|
||||||
|
<group name="" protocol="TCP">
|
||||||
|
<!--
|
||||||
|
需要将本地node的addr与port列在此处。
|
||||||
|
同一个<node>节点值只能存在一个<group>节点内,即同一个addr+port只能属于一个group。
|
||||||
|
addr: required IP地址
|
||||||
|
port: required 端口
|
||||||
|
-->
|
||||||
|
<node addr="127.0.0.1" port="7070"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
全局的数据源设置, 可以是CacheSource、DataSource, JDBC的DataSource通常通过persistence.xml配置,此处多用于CacheSource的配置
|
||||||
|
name: 资源名,用于依赖注入。
|
||||||
|
value: 类名,必须是CacheSource或DataSource的子类,且必须实现Service接口。如果是DataSource.class,系统自动映射成DataJdbcSource.class
|
||||||
|
groups: 指定groups。
|
||||||
|
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
|
||||||
|
-->
|
||||||
|
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
|
||||||
|
<node addr="127.0.0.1" port="7070"/>
|
||||||
|
</source>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Application启动的监听事件,可配置多个节点
|
||||||
|
value: 类名,必须是ApplicationListener的子类
|
||||||
|
-->
|
||||||
|
<listener value="org.redkalex.xxx.XXXApplicationListener"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点全局唯一】
|
||||||
|
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
|
||||||
|
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
||||||
|
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
||||||
|
load: 加载文件,多个用;隔开。
|
||||||
|
默认置入的system.property.的有:
|
||||||
|
System.setProperty("redkale.net.transport.poolmaxconns", "100");
|
||||||
|
System.setProperty("redkale.net.transport.pinginterval", "30");
|
||||||
|
System.setProperty("redkale.net.transport.checkinterval", "30");
|
||||||
|
System.setProperty("redkale.convert.tiny", "true");
|
||||||
|
System.setProperty("redkale.convert.pool.size", "128");
|
||||||
|
System.setProperty("redkale.convert.writer.buffer.defsize", "4096");
|
||||||
|
|
||||||
|
<properties>节点下也可包含非<property>节点.
|
||||||
|
非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
|
||||||
|
-->
|
||||||
|
<properties load="config.properties">
|
||||||
|
<property name="system.property.yyyy" value="YYYYYY"/>
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
<!--
|
||||||
|
protocol: required server所启动的协议,Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
|
||||||
|
name: 服务的名称,用于监控识别,一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
|
||||||
|
host: 服务所占address , 默认: 0.0.0.0
|
||||||
|
port: required 服务所占端口
|
||||||
|
root: 如果是web类型服务,则包含页面 默认:{APP_HOME}/root
|
||||||
|
lib: server额外的class目录, 默认为${APP_HOME}/libs/*;
|
||||||
|
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||||
|
charset: 文本编码, 默认: UTF-8
|
||||||
|
backlog: 默认10K
|
||||||
|
threads【已废弃】: 线程数, 默认: CPU核数*2,最小8个【已废弃 @since 2.3.0】
|
||||||
|
maxconns: 最大连接数, 小于1表示无限制, 默认: 0
|
||||||
|
maxbody: request.body最大值, 默认: 64K
|
||||||
|
bufferCapacity: ByteBuffer的初始化大小, TCP默认: 32K; (HTTP 2.0、WebSocket,必须要16k以上); UDP默认: 1350B
|
||||||
|
bufferPoolSize: ByteBuffer池的大小,默认: 线程数*4
|
||||||
|
responsePoolSize: Response池的大小,默认: 1024
|
||||||
|
aliveTimeoutSeconds: KeepAlive读操作超时秒数, 默认30, 0表示永久不超时; -1表示禁止KeepAlive
|
||||||
|
readTimeoutSeconds: 读操作超时秒数, 默认0, 表示永久不超时
|
||||||
|
writeTimeoutSeconds: 写操作超时秒数, 默认0, 表示永久不超时
|
||||||
|
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类,必须是org.redkale.boot.NodeInterceptor的子类,默认为null
|
||||||
|
-->
|
||||||
|
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点在<server>中唯一】
|
||||||
|
builder: 创建SSLContext的实现类, 可自定义,必须是org.redkale.net.SSLBuilder的子类
|
||||||
|
sslProvider: java.security.Provider自定义的实现类,如第三方: org.conscrypt.OpenSSLProvider、org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
|
jsseProvider: java.security.Provider自定义的实现类,如第三方: org.conscrypt.JSSEProvider、 org.bouncycastle.jce.provider.BouncyCastleJsseProvider
|
||||||
|
protocol: TLS版本,默认值: TLS
|
||||||
|
protocols: 设置setEnabledProtocols, 多个用,隔开 如: TLSv1.2,TLSv1.3
|
||||||
|
clientAuth: WANT/NEED/NONE, 默认值: NONE
|
||||||
|
ciphers: 设置setEnabledCipherSuites, 多个用,隔开 如: TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256
|
||||||
|
keystorePass: KEY密码
|
||||||
|
keystoreFile: KEY文件 .jks
|
||||||
|
keystoreType: KEY类型, 默认值为JKS
|
||||||
|
keystoreAlgorithm: KEY文件的algorithm, 默认值为SunX509
|
||||||
|
truststorePass: TRUST密码
|
||||||
|
truststoreFile: TRUST文件
|
||||||
|
truststoreType: TRUST类型, 默认值为JKS
|
||||||
|
truststoreAlgorithm: TRUST文件的algorithm, 默认值为SunX509
|
||||||
|
-->
|
||||||
|
<ssl builder=""/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
加载所有的Service服务;
|
||||||
|
在同一个进程中同一个name同一类型的Service将共用同一个实例
|
||||||
|
autoload="true" 默认值. 自动加载classpath下所有的Service类
|
||||||
|
autoload="false" 需要显著的指定Service类
|
||||||
|
mq: 所属的MQ管理器,当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
|
||||||
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
groups: 所属组的节点,多个节点值用;隔开,如果配置文件中存在多个SNCP协议的Server节点,需要显式指定group属性.
|
||||||
|
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
|
||||||
|
当 protocol != SNCP 时 group只能是空或者一个group的节点值,不能为多个节点值。
|
||||||
|
特殊值"$cluster", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息
|
||||||
|
-->
|
||||||
|
<services autoload="true" includes="" excludes="">
|
||||||
|
|
||||||
|
<!-- 显著加载指定的Service的接口类 -->
|
||||||
|
<service value="com.xxx.XXX1Service"/>
|
||||||
|
<!--
|
||||||
|
name: 显式指定name,覆盖默认的空字符串值。 注意: name不能包含$符号。
|
||||||
|
mq: 所属的MQ管理器,当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
|
||||||
|
groups: 显式指定groups,覆盖<services>节点的groups默认值。
|
||||||
|
ignore: 是否禁用, 默认为false。
|
||||||
|
-->
|
||||||
|
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
|
||||||
|
<!-- 给Service增加配置属性 -->
|
||||||
|
<service value="com.xxx.XXX1Service">
|
||||||
|
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
</service>
|
||||||
|
</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的核心配置项
|
||||||
|
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置,系统会自动生成)
|
||||||
|
path: servlet的ContextPath前缀 默认为空 【注: 开启MQ时,该字段失效】
|
||||||
|
base: REST服务的BaseServlet,必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
|
||||||
|
mq: 所属的MQ管理器, 存在该属性表示RestService的请求来自于消息总线 【注: 开启MQ时,path字段失效】
|
||||||
|
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
|
||||||
|
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
-->
|
||||||
|
<rest path="/pipes" base="org.redkale.net.http.HttpServlet" autoload="true" includes="" excludes="">
|
||||||
|
<!--
|
||||||
|
value: Service类名,列出的表示必须被加载的Service对象
|
||||||
|
ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
|
||||||
|
-->
|
||||||
|
<service value="com.xxx.XXXXService"/>
|
||||||
|
<!--
|
||||||
|
value: WebSocket类名,列出的表示必须被加载且标记为@RestWebSocket的WebSocket对象
|
||||||
|
ignore: 是否忽略,设置为true则不会加载该RestWebSocket对象,默认值为false
|
||||||
|
-->
|
||||||
|
<websocket value="com.xxx.XXXXRestWebSocket"/>
|
||||||
|
</rest>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点在<server>中唯一】
|
||||||
|
当Server为HTTP协议时, request节点才有效。
|
||||||
|
remoteaddr 节点: 替换请求方节点的IP地址, 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。
|
||||||
|
且value值只能是以request.headers.开头,表示从request.headers中获取对应的header值。
|
||||||
|
例如下面例子获取request.getRemoteAddr()值,如果header存在X-RemoteAddress值则返回X-RemoteAddress值,不存在返回getRemoteAddress()。
|
||||||
|
-->
|
||||||
|
<request>
|
||||||
|
<remoteaddr value="request.headers.X-RemoteAddress"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
【节点在<server>中唯一】
|
||||||
|
当Server为HTTP协议时, response节点才有效。
|
||||||
|
contenttype: plain值为调用finish时的ContentType; 默认值: text/plain; charset=utf-8
|
||||||
|
json值为调用finishJson时的ContentType; 默认值: application/json; charset=utf-8
|
||||||
|
defcookie 节点: 当response里输出的cookie没有指定domain 和path时,使用该节点的默认值。
|
||||||
|
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
|
||||||
|
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
|
||||||
|
例如下面例子是在Response输出header时添加两个header(一个addHeader, 一个setHeader)。
|
||||||
|
options 节点: 设置了该节点且auto=true,当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
|
||||||
|
date 节点: 设置了该节点且period有值(单位:毫秒);返回response会包含Date头信息,默认为period=0
|
||||||
|
period=0表示实时获取当前时间;
|
||||||
|
period<0表示不设置date;
|
||||||
|
period>0表示定时获取时间; 设置1000表示每秒刷新Date时间
|
||||||
|
-->
|
||||||
|
<response>
|
||||||
|
<content-type plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/>
|
||||||
|
<defcookie domain="" path=""/>
|
||||||
|
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
|
||||||
|
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/>
|
||||||
|
<setheader name="Access-Control-Allow-Credentials" value="true"/>
|
||||||
|
<options auto="true" />
|
||||||
|
<date period="0" />
|
||||||
|
</response>
|
||||||
|
<!--
|
||||||
|
【节点在<server>中唯一】
|
||||||
|
当Server为HTTP协议时,render才有效. 指定输出引擎的实现类
|
||||||
|
value: 输出引擎的实现类, 必须是org.redkale.net.http.HttpRender的子类
|
||||||
|
suffixs: 引擎文件名后缀,多个用;隔开,默认值为: .htel
|
||||||
|
-->
|
||||||
|
<render value="org.redkalex.htel.HttpTemplateRender" suffixs=".htel"/>
|
||||||
|
<!--
|
||||||
|
【节点在<server>中唯一】
|
||||||
|
当Server为HTTP协议时,ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
|
||||||
|
webroot: web资源的根目录, 默认取server节点中的root值
|
||||||
|
servlet: 静态资源HttpServlet的实现,默认使用HttpResourceServlet
|
||||||
|
index : 启始页,默认值:index.html
|
||||||
|
-->
|
||||||
|
<resource-servlet webroot="root" index="index.html">
|
||||||
|
<!--
|
||||||
|
【节点在<resource-servlet>中唯一】
|
||||||
|
资源缓存的配置, 默认存在一个含默认属性的caches节点
|
||||||
|
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存, 单位可以是B、K、M、G,不区分大小写
|
||||||
|
lengthmax: 可缓存的文件大小上限, 默认: 1M(超过1M的文件不会被缓存)
|
||||||
|
watch: 是否监控缓存文件的变化, 默认为false,不监控
|
||||||
|
-->
|
||||||
|
<cache limit="0M" lengthmax="1M" watch="false"/>
|
||||||
|
<!--
|
||||||
|
支持类似nginx中的rewrite, 目前只支持静态资源对静态资源的跳转。
|
||||||
|
type: 匹配的类型, 目前只支持location(匹配requestURI), 默认: location
|
||||||
|
match: 匹配的正则表达式
|
||||||
|
forward: 需跳转后的资源链接
|
||||||
|
例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html
|
||||||
|
-->
|
||||||
|
<rewrite type="location" match="^/([^-]+)-[^-\.]+\.html(.*)" forward="/$1.html"/>
|
||||||
|
</resource-servlet>
|
||||||
|
<!--
|
||||||
|
加载所有的Servlet服务;
|
||||||
|
path: servlet的ContextPath前缀 默认为空
|
||||||
|
autoload="true" 默认值. 自动加载classpath下所有的Servlet类
|
||||||
|
autoload="false" 需要显著的指定Service类
|
||||||
|
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||||
|
-->
|
||||||
|
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
||||||
|
<!--
|
||||||
|
显著加载指定的Servlet类
|
||||||
|
value=: Servlet类名。必须与Server的协议层相同,HTTP必须是HttpServlet
|
||||||
|
ignore: 是否禁用, 默认为false。
|
||||||
|
-->
|
||||||
|
<servlet value="com.xxx.XXX1Servlet" />
|
||||||
|
<servlet value="com.xxx.XXX2Servlet" />
|
||||||
|
<servlet value="com.xxx.XXX3Servlet" >
|
||||||
|
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||||
|
<property name="yyyyyy" value="YYYYYYYY"/>
|
||||||
|
</servlet>
|
||||||
|
</servlets>
|
||||||
|
</server>
|
||||||
|
|
||||||
|
<server protocol="SNCP" host="127.0.0.1" port="7070" root="root" lib="">
|
||||||
|
<!-- 参数完全同上 -->
|
||||||
|
<services autoload="true" includes="" excludes="" />
|
||||||
|
</server>
|
||||||
|
</application>
|
||||||
@@ -11,13 +11,15 @@ javax.level = INFO
|
|||||||
com.sun.level = INFO
|
com.sun.level = INFO
|
||||||
|
|
||||||
#java.util.logging.FileHandler.level = FINE
|
#java.util.logging.FileHandler.level = FINE
|
||||||
#10M
|
|
||||||
java.util.logging.FileHandler.limit = 10485760
|
java.util.logging.FileHandler.limit = 20M
|
||||||
java.util.logging.FileHandler.count = 100
|
java.util.logging.FileHandler.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
|
||||||
|
#\u9700\u8981\u5c4f\u853d\u6d88\u606f\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f
|
||||||
|
java.util.logging.FileHandler.denyreg =
|
||||||
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,32 +3,27 @@
|
|||||||
<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的数据库驱动一般无需设置
|
DataSource的实现类,没有设置默认为org.redkale.source.DataJdbcSource的实现,使用常规基于JDBC的数据库驱动一般无需设置
|
||||||
-->
|
-->
|
||||||
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
|
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
|
||||||
|
|
||||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
|
|
||||||
<!--
|
<!--
|
||||||
javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。
|
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存, 非NONE字样统一视为ALL
|
||||||
为了兼容用户习惯,Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系:
|
|
||||||
org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource
|
|
||||||
org.postgresql.Driver —————— org.postgresql.ds.PGConnectionPoolDataSource
|
|
||||||
com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
|
|
||||||
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
|
|
||||||
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
|
|
||||||
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
|
|
||||||
并且如果JDBC驱动是以上几个版本,javax.persistence.jdbc.driver属性都可以省略,Redkale会根据javax.persistence.jdbc.url的值来识别驱动
|
|
||||||
-->
|
-->
|
||||||
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
<property name="javax.persistence.cachemode" value="ALL"/>
|
||||||
|
<!--
|
||||||
|
是否自动建表当表不存在的时候, 目前只支持mysql、postgres, 默认为false
|
||||||
|
-->
|
||||||
|
<property name="javax.persistence.table.autoddl" value="false"/>
|
||||||
|
|
||||||
|
<!-- 多个URL用;隔开,如分布式SearchSource需要配多个URL -->
|
||||||
|
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
|
||||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||||
<property name="javax.persistence.jdbc.password" value="123456"/>
|
<property name="javax.persistence.jdbc.password" value="123456"/>
|
||||||
|
|
||||||
<!-- 最大连接数,默认值:CPU数*16 -->
|
<!-- 最大连接数,默认值:CPU数 -->
|
||||||
<property name="javax.persistence.connections.limit" value="32"/>
|
<property name="javax.persistence.connections.limit" value="12"/>
|
||||||
|
|
||||||
<!-- 包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL的语句 -->
|
<!-- 包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL的语句 -->
|
||||||
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
|
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
|
||||||
@@ -36,17 +31,15 @@
|
|||||||
|
|
||||||
<!-- 复制表结构的SQL模板,Redkale内置了MySQL的语句 -->
|
<!-- 复制表结构的SQL模板,Redkale内置了MySQL的语句 -->
|
||||||
<property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
|
<property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
|
||||||
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
|
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}"/>
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
</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"/>
|
||||||
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
|
||||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||||
<property name="javax.persistence.jdbc.password" value="123456"/>
|
<property name="javax.persistence.jdbc.password" value="123456"/>
|
||||||
</properties>
|
</properties>
|
||||||
39
src/main/java/javax/annotation/Priority.java
Normal file
39
src/main/java/javax/annotation/Priority.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级值
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int value();
|
||||||
|
}
|
||||||
83
src/main/java/javax/annotation/Resource.java
Normal file
83
src/main/java/javax/annotation/Resource.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AuthenticationType
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public enum AuthenticationType {
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
CONTAINER,
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
APPLICATION
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源名称
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 依赖注入的类型
|
||||||
|
*
|
||||||
|
* @return Class
|
||||||
|
*/
|
||||||
|
public Class<?> type() default Object.class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return AuthenticationType
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public boolean shareable() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public String description() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public String mappedName() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public String lookup() default "";
|
||||||
|
}
|
||||||
@@ -51,4 +51,12 @@ public @interface Cacheable {
|
|||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int interval() default 0;
|
int interval() default 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataSource是否直接返回对象的真实引用, 而不是copy一份
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean direct() default false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -81,12 +81,19 @@ public @interface Column {
|
|||||||
boolean unique() default false;
|
boolean unique() default false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Optional) Whether the database column is nullable.
|
* (Optional) Whether the database column is required.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
boolean nullable() default true;
|
boolean nullable() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for OpenAPI Specification 3
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
String example() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Optional) Whether the column is included in SQL INSERT
|
* (Optional) Whether the column is included in SQL INSERT
|
||||||
* statements generated by the persistence provider.
|
* statements generated by the persistence provider.
|
||||||
@@ -109,11 +116,13 @@ public @interface Column {
|
|||||||
*
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
String table() default "";
|
String table() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Optional) The column length. (Applies only if a
|
* (Optional) The column length. (Applies only if a
|
||||||
* string-valued column is used.)
|
* string-valued column is used.)
|
||||||
|
* if type==String and length == 65535 then sqltype is text
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@@ -15,9 +15,7 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package javax.persistence;
|
package javax.persistence;
|
||||||
|
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.*;
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import static java.lang.annotation.ElementType.TYPE;
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
@@ -27,6 +25,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||||||
*
|
*
|
||||||
* @since Java Persistence 1.0
|
* @since Java Persistence 1.0
|
||||||
*/
|
*/
|
||||||
|
@Inherited
|
||||||
@Documented
|
@Documented
|
||||||
@Target(TYPE)
|
@Target(TYPE)
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@@ -45,7 +45,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see Column
|
* @see Column
|
||||||
* @see GeneratedValue
|
* see GeneratedValue
|
||||||
*
|
*
|
||||||
* @since Java Persistence 1.0
|
* @since Java Persistence 1.0
|
||||||
*/
|
*/
|
||||||
@@ -82,6 +82,11 @@ public @interface Table {
|
|||||||
*/
|
*/
|
||||||
Index[] indexes() default {};
|
Index[] indexes() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* comment
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
String comment() default "";
|
String comment() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
44
src/main/java/module-info.java
Normal file
44
src/main/java/module-info.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* see: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
module redkale {
|
||||||
|
|
||||||
|
requires java.base;
|
||||||
|
requires java.logging;
|
||||||
|
requires java.net.http;
|
||||||
|
requires java.sql;
|
||||||
|
requires jdk.unsupported; //sun.misc.Unsafe
|
||||||
|
|
||||||
|
exports javax.annotation;
|
||||||
|
exports javax.persistence;
|
||||||
|
|
||||||
|
exports org.redkale.asm;
|
||||||
|
exports org.redkale.boot;
|
||||||
|
exports org.redkale.boot.watch;
|
||||||
|
exports org.redkale.cluster;
|
||||||
|
exports org.redkale.convert;
|
||||||
|
exports org.redkale.convert.bson;
|
||||||
|
exports org.redkale.convert.ext;
|
||||||
|
exports org.redkale.convert.json;
|
||||||
|
exports org.redkale.mq;
|
||||||
|
exports org.redkale.net;
|
||||||
|
exports org.redkale.net.client;
|
||||||
|
exports org.redkale.net.http;
|
||||||
|
exports org.redkale.net.sncp;
|
||||||
|
exports org.redkale.service;
|
||||||
|
exports org.redkale.source;
|
||||||
|
exports org.redkale.util;
|
||||||
|
exports org.redkale.watch;
|
||||||
|
|
||||||
|
uses org.redkale.mq.MessageAgent;
|
||||||
|
uses org.redkale.cluster.ClusterAgent;
|
||||||
|
uses org.redkale.convert.ConvertProvider;
|
||||||
|
uses org.redkale.source.CacheSourceProvider;
|
||||||
|
uses org.redkale.source.DataSourceProvider;
|
||||||
|
uses org.redkale.util.ResourceInjectLoader;
|
||||||
|
|
||||||
|
}
|
||||||
195
src/main/java/org/redkale/asm/AnnotationVisitor.java
Normal file
195
src/main/java/org/redkale/asm/AnnotationVisitor.java
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A visitor to visit a Java annotation. The methods of this class must be
|
||||||
|
* called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
|
||||||
|
* <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
* @author Eugene Kuleshov
|
||||||
|
*/
|
||||||
|
public abstract class AnnotationVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ASM API version implemented by this visitor. The value of this field
|
||||||
|
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
protected final int api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The annotation visitor to which this visitor must delegate method calls.
|
||||||
|
* May be null.
|
||||||
|
*/
|
||||||
|
protected AnnotationVisitor av;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link AnnotationVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor(final int api) {
|
||||||
|
this(api, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link AnnotationVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
* @param av
|
||||||
|
* the annotation visitor to which this visitor must delegate
|
||||||
|
* method calls. May be null.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
|
||||||
|
this.api = api;
|
||||||
|
this.av = av;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a primitive value of the annotation.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the value name.
|
||||||
|
* @param value
|
||||||
|
* the actual value, whose type must be {@link Byte},
|
||||||
|
* {@link Boolean}, {@link Character}, {@link Short},
|
||||||
|
* {@link Integer} , {@link Long}, {@link Float}, {@link Double},
|
||||||
|
* {@link String} or {@link Type} of OBJECT or ARRAY sort. This
|
||||||
|
* value can also be an array of byte, boolean, short, char, int,
|
||||||
|
* long, float or double values (this is equivalent to using
|
||||||
|
* {@link #visitArray visitArray} and visiting each array element
|
||||||
|
* in turn, but is more convenient).
|
||||||
|
*/
|
||||||
|
public void visit(String name, Object value) {
|
||||||
|
if (av != null) {
|
||||||
|
av.visit(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an enumeration value of the annotation.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the value name.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the enumeration class.
|
||||||
|
* @param value
|
||||||
|
* the actual enumeration value.
|
||||||
|
*/
|
||||||
|
public void visitEnum(String name, String desc, String value) {
|
||||||
|
if (av != null) {
|
||||||
|
av.visitEnum(name, desc, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a nested annotation value of the annotation.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the value name.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the nested annotation class.
|
||||||
|
* @return a visitor to visit the actual nested annotation value, or
|
||||||
|
* <tt>null</tt> if this visitor is not interested in visiting this
|
||||||
|
* nested annotation. <i>The nested annotation value must be fully
|
||||||
|
* visited before calling other methods on this annotation
|
||||||
|
* visitor</i>.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||||
|
if (av != null) {
|
||||||
|
return av.visitAnnotation(name, desc);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an array value of the annotation. Note that arrays of primitive
|
||||||
|
* types (such as byte, boolean, short, char, int, long, float or double)
|
||||||
|
* can be passed as value to {@link #visit visit}. This is what
|
||||||
|
* {@link ClassReader} does.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the value name.
|
||||||
|
* @return a visitor to visit the actual array value elements, or
|
||||||
|
* <tt>null</tt> if this visitor is not interested in visiting these
|
||||||
|
* values. The 'name' parameters passed to the methods of this
|
||||||
|
* visitor are ignored. <i>All the array values must be visited
|
||||||
|
* before calling other methods on this annotation visitor</i>.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitArray(String name) {
|
||||||
|
if (av != null) {
|
||||||
|
return av.visitArray(name);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the end of the annotation.
|
||||||
|
*/
|
||||||
|
public void visitEnd() {
|
||||||
|
if (av != null) {
|
||||||
|
av.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
400
src/main/java/org/redkale/asm/AnnotationWriter.java
Normal file
400
src/main/java/org/redkale/asm/AnnotationWriter.java
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link AnnotationVisitor} that generates annotations in bytecode form.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
* @author Eugene Kuleshov
|
||||||
|
*/
|
||||||
|
final class AnnotationWriter extends AnnotationVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class writer to which this annotation must be added.
|
||||||
|
*/
|
||||||
|
private final ClassWriter cw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of values in this annotation.
|
||||||
|
*/
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
|
||||||
|
* writers used for annotation default and annotation arrays use unnamed
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
private final boolean named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The annotation values in bytecode form. This byte vector only contains
|
||||||
|
* the values themselves, i.e. the number of values must be stored as a
|
||||||
|
* unsigned short just before these bytes.
|
||||||
|
*/
|
||||||
|
private final ByteVector bv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The byte vector to be used to store the number of values of this
|
||||||
|
* annotation. See {@link #bv}.
|
||||||
|
*/
|
||||||
|
private final ByteVector parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where the number of values of this annotation must be stored in
|
||||||
|
* {@link #parent}.
|
||||||
|
*/
|
||||||
|
private final int offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next annotation writer. This field is used to store annotation lists.
|
||||||
|
*/
|
||||||
|
AnnotationWriter next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous annotation writer. This field is used to store annotation lists.
|
||||||
|
*/
|
||||||
|
AnnotationWriter prev;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constructor
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link AnnotationWriter}.
|
||||||
|
*
|
||||||
|
* @param cw
|
||||||
|
* the class writer to which this annotation must be added.
|
||||||
|
* @param named
|
||||||
|
* <tt>true<tt> if values are named, <tt>false</tt> otherwise.
|
||||||
|
* @param bv
|
||||||
|
* where the annotation values must be stored.
|
||||||
|
* @param parent
|
||||||
|
* where the number of annotation values must be stored.
|
||||||
|
* @param offset
|
||||||
|
* where in <tt>parent</tt> the number of annotation values must
|
||||||
|
* be stored.
|
||||||
|
*/
|
||||||
|
AnnotationWriter(final ClassWriter cw, final boolean named,
|
||||||
|
final ByteVector bv, final ByteVector parent, final int offset) {
|
||||||
|
super(Opcodes.ASM6);
|
||||||
|
this.cw = cw;
|
||||||
|
this.named = named;
|
||||||
|
this.bv = bv;
|
||||||
|
this.parent = parent;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Implementation of the AnnotationVisitor abstract class
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(final String name, final Object value) {
|
||||||
|
++size;
|
||||||
|
if (named) {
|
||||||
|
bv.putShort(cw.newUTF8(name));
|
||||||
|
}
|
||||||
|
if (value instanceof String) {
|
||||||
|
bv.put12('s', cw.newUTF8((String) value));
|
||||||
|
} else if (value instanceof Byte) {
|
||||||
|
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
int v = ((Boolean) value).booleanValue() ? 1 : 0;
|
||||||
|
bv.put12('Z', cw.newInteger(v).index);
|
||||||
|
} else if (value instanceof Character) {
|
||||||
|
bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
|
||||||
|
} else if (value instanceof Short) {
|
||||||
|
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
|
||||||
|
} else if (value instanceof Type) {
|
||||||
|
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
|
||||||
|
} else if (value instanceof byte[]) {
|
||||||
|
byte[] v = (byte[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('B', cw.newInteger(v[i]).index);
|
||||||
|
}
|
||||||
|
} else if (value instanceof boolean[]) {
|
||||||
|
boolean[] v = (boolean[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
|
||||||
|
}
|
||||||
|
} else if (value instanceof short[]) {
|
||||||
|
short[] v = (short[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('S', cw.newInteger(v[i]).index);
|
||||||
|
}
|
||||||
|
} else if (value instanceof char[]) {
|
||||||
|
char[] v = (char[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('C', cw.newInteger(v[i]).index);
|
||||||
|
}
|
||||||
|
} else if (value instanceof int[]) {
|
||||||
|
int[] v = (int[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('I', cw.newInteger(v[i]).index);
|
||||||
|
}
|
||||||
|
} else if (value instanceof long[]) {
|
||||||
|
long[] v = (long[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('J', cw.newLong(v[i]).index);
|
||||||
|
}
|
||||||
|
} else if (value instanceof float[]) {
|
||||||
|
float[] v = (float[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('F', cw.newFloat(v[i]).index);
|
||||||
|
}
|
||||||
|
} else if (value instanceof double[]) {
|
||||||
|
double[] v = (double[]) value;
|
||||||
|
bv.put12('[', v.length);
|
||||||
|
for (int i = 0; i < v.length; i++) {
|
||||||
|
bv.put12('D', cw.newDouble(v[i]).index);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Item i = cw.newConstItem(value);
|
||||||
|
bv.put12(".s.IFJDCS".charAt(i.type), i.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnum(final String name, final String desc,
|
||||||
|
final String value) {
|
||||||
|
++size;
|
||||||
|
if (named) {
|
||||||
|
bv.putShort(cw.newUTF8(name));
|
||||||
|
}
|
||||||
|
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationVisitor visitAnnotation(final String name,
|
||||||
|
final String desc) {
|
||||||
|
++size;
|
||||||
|
if (named) {
|
||||||
|
bv.putShort(cw.newUTF8(name));
|
||||||
|
}
|
||||||
|
// write tag and type, and reserve space for values count
|
||||||
|
bv.put12('@', cw.newUTF8(desc)).putShort(0);
|
||||||
|
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationVisitor visitArray(final String name) {
|
||||||
|
++size;
|
||||||
|
if (named) {
|
||||||
|
bv.putShort(cw.newUTF8(name));
|
||||||
|
}
|
||||||
|
// write tag, and reserve space for array size
|
||||||
|
bv.put12('[', 0);
|
||||||
|
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
if (parent != null) {
|
||||||
|
byte[] data = parent.data;
|
||||||
|
data[offset] = (byte) (size >>> 8);
|
||||||
|
data[offset + 1] = (byte) size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Utility methods
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of this annotation writer list.
|
||||||
|
*
|
||||||
|
* @return the size of this annotation writer list.
|
||||||
|
*/
|
||||||
|
int getSize() {
|
||||||
|
int size = 0;
|
||||||
|
AnnotationWriter aw = this;
|
||||||
|
while (aw != null) {
|
||||||
|
size += aw.bv.length;
|
||||||
|
aw = aw.next;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the annotations of this annotation writer list into the given byte
|
||||||
|
* vector.
|
||||||
|
*
|
||||||
|
* @param out
|
||||||
|
* where the annotations must be put.
|
||||||
|
*/
|
||||||
|
void put(final ByteVector out) {
|
||||||
|
int n = 0;
|
||||||
|
int size = 2;
|
||||||
|
AnnotationWriter aw = this;
|
||||||
|
AnnotationWriter last = null;
|
||||||
|
while (aw != null) {
|
||||||
|
++n;
|
||||||
|
size += aw.bv.length;
|
||||||
|
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||||
|
aw.prev = last;
|
||||||
|
last = aw;
|
||||||
|
aw = aw.next;
|
||||||
|
}
|
||||||
|
out.putInt(size);
|
||||||
|
out.putShort(n);
|
||||||
|
aw = last;
|
||||||
|
while (aw != null) {
|
||||||
|
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||||
|
aw = aw.prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the given annotation lists into the given byte vector.
|
||||||
|
*
|
||||||
|
* @param panns
|
||||||
|
* an array of annotation writer lists.
|
||||||
|
* @param off
|
||||||
|
* index of the first annotation to be written.
|
||||||
|
* @param out
|
||||||
|
* where the annotations must be put.
|
||||||
|
*/
|
||||||
|
static void put(final AnnotationWriter[] panns, final int off,
|
||||||
|
final ByteVector out) {
|
||||||
|
int size = 1 + 2 * (panns.length - off);
|
||||||
|
for (int i = off; i < panns.length; ++i) {
|
||||||
|
size += panns[i] == null ? 0 : panns[i].getSize();
|
||||||
|
}
|
||||||
|
out.putInt(size).putByte(panns.length - off);
|
||||||
|
for (int i = off; i < panns.length; ++i) {
|
||||||
|
AnnotationWriter aw = panns[i];
|
||||||
|
AnnotationWriter last = null;
|
||||||
|
int n = 0;
|
||||||
|
while (aw != null) {
|
||||||
|
++n;
|
||||||
|
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||||
|
aw.prev = last;
|
||||||
|
last = aw;
|
||||||
|
aw = aw.next;
|
||||||
|
}
|
||||||
|
out.putShort(n);
|
||||||
|
aw = last;
|
||||||
|
while (aw != null) {
|
||||||
|
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||||
|
aw = aw.prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the given type reference and type path into the given bytevector.
|
||||||
|
* LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* a reference to the annotated type. See {@link TypeReference}.
|
||||||
|
* @param typePath
|
||||||
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
|
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||||
|
* @param out
|
||||||
|
* where the type reference and type path must be put.
|
||||||
|
*/
|
||||||
|
static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
|
||||||
|
switch (typeRef >>> 24) {
|
||||||
|
case 0x00: // CLASS_TYPE_PARAMETER
|
||||||
|
case 0x01: // METHOD_TYPE_PARAMETER
|
||||||
|
case 0x16: // METHOD_FORMAL_PARAMETER
|
||||||
|
out.putShort(typeRef >>> 16);
|
||||||
|
break;
|
||||||
|
case 0x13: // FIELD
|
||||||
|
case 0x14: // METHOD_RETURN
|
||||||
|
case 0x15: // METHOD_RECEIVER
|
||||||
|
out.putByte(typeRef >>> 24);
|
||||||
|
break;
|
||||||
|
case 0x47: // CAST
|
||||||
|
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||||
|
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
|
||||||
|
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||||
|
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
|
||||||
|
out.putInt(typeRef);
|
||||||
|
break;
|
||||||
|
// case 0x10: // CLASS_EXTENDS
|
||||||
|
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
|
||||||
|
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
|
||||||
|
// case 0x17: // THROWS
|
||||||
|
// case 0x42: // EXCEPTION_PARAMETER
|
||||||
|
// case 0x43: // INSTANCEOF
|
||||||
|
// case 0x44: // NEW
|
||||||
|
// case 0x45: // CONSTRUCTOR_REFERENCE
|
||||||
|
// case 0x46: // METHOD_REFERENCE
|
||||||
|
default:
|
||||||
|
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (typePath == null) {
|
||||||
|
out.putByte(0);
|
||||||
|
} else {
|
||||||
|
int length = typePath.b[typePath.offset] * 2 + 1;
|
||||||
|
out.putByteArray(typePath.b, typePath.offset, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
364
src/main/java/org/redkale/asm/Attribute.java
Normal file
364
src/main/java/org/redkale/asm/Attribute.java
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A non standard class, field, method or code attribute.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
* @author Eugene Kuleshov
|
||||||
|
*/
|
||||||
|
public class Attribute {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this attribute.
|
||||||
|
*/
|
||||||
|
public final String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw value of this attribute, used only for unknown attributes.
|
||||||
|
*/
|
||||||
|
byte[] value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next attribute in this attribute list. May be <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
Attribute next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new empty attribute.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* the type of the attribute.
|
||||||
|
*/
|
||||||
|
protected Attribute(final String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <tt>true</tt> if this type of attribute is unknown. The default
|
||||||
|
* implementation of this method always returns <tt>true</tt>.
|
||||||
|
*
|
||||||
|
* @return <tt>true</tt> if this type of attribute is unknown.
|
||||||
|
*/
|
||||||
|
public boolean isUnknown() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <tt>true</tt> if this type of attribute is a code attribute.
|
||||||
|
*
|
||||||
|
* @return <tt>true</tt> if this type of attribute is a code attribute.
|
||||||
|
*/
|
||||||
|
public boolean isCodeAttribute() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the labels corresponding to this attribute.
|
||||||
|
*
|
||||||
|
* @return the labels corresponding to this attribute, or <tt>null</tt> if
|
||||||
|
* this attribute is not a code attribute that contains labels.
|
||||||
|
*/
|
||||||
|
protected Label[] getLabels() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a {@link #type type} attribute. This method must return a
|
||||||
|
* <i>new</i> {@link Attribute} object, of type {@link #type type},
|
||||||
|
* corresponding to the <tt>len</tt> bytes starting at the given offset, in
|
||||||
|
* the given class reader.
|
||||||
|
*
|
||||||
|
* @param cr
|
||||||
|
* the class that contains the attribute to be read.
|
||||||
|
* @param off
|
||||||
|
* index of the first byte of the attribute's content in
|
||||||
|
* {@link ClassReader#b cr.b}. The 6 attribute header bytes,
|
||||||
|
* containing the type and the length of the attribute, are not
|
||||||
|
* taken into account here.
|
||||||
|
* @param len
|
||||||
|
* the length of the attribute's content.
|
||||||
|
* @param buf
|
||||||
|
* buffer to be used to call {@link ClassReader#readUTF8
|
||||||
|
* readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
|
||||||
|
* or {@link ClassReader#readConst readConst}.
|
||||||
|
* @param codeOff
|
||||||
|
* index of the first byte of code's attribute content in
|
||||||
|
* {@link ClassReader#b cr.b}, or -1 if the attribute to be read
|
||||||
|
* is not a code attribute. The 6 attribute header bytes,
|
||||||
|
* containing the type and the length of the attribute, are not
|
||||||
|
* taken into account here.
|
||||||
|
* @param labels
|
||||||
|
* the labels of the method's code, or <tt>null</tt> if the
|
||||||
|
* attribute to be read is not a code attribute.
|
||||||
|
* @return a <i>new</i> {@link Attribute} object corresponding to the given
|
||||||
|
* bytes.
|
||||||
|
*/
|
||||||
|
protected Attribute read(final ClassReader cr, final int off,
|
||||||
|
final int len, final char[] buf, final int codeOff,
|
||||||
|
final Label[] labels) {
|
||||||
|
Attribute attr = new Attribute(type);
|
||||||
|
attr.value = new byte[len];
|
||||||
|
System.arraycopy(cr.b, off, attr.value, 0, len);
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the byte array form of this attribute.
|
||||||
|
*
|
||||||
|
* @param cw
|
||||||
|
* the class to which this attribute must be added. This
|
||||||
|
* parameter can be used to add to the constant pool of this
|
||||||
|
* class the items that corresponds to this attribute.
|
||||||
|
* @param code
|
||||||
|
* the bytecode of the method corresponding to this code
|
||||||
|
* attribute, or <tt>null</tt> if this attribute is not a code
|
||||||
|
* attributes.
|
||||||
|
* @param len
|
||||||
|
* the length of the bytecode of the method corresponding to this
|
||||||
|
* code attribute, or <tt>null</tt> if this attribute is not a
|
||||||
|
* code attribute.
|
||||||
|
* @param maxStack
|
||||||
|
* the maximum stack size of the method corresponding to this
|
||||||
|
* code attribute, or -1 if this attribute is not a code
|
||||||
|
* attribute.
|
||||||
|
* @param maxLocals
|
||||||
|
* the maximum number of local variables of the method
|
||||||
|
* corresponding to this code attribute, or -1 if this attribute
|
||||||
|
* is not a code attribute.
|
||||||
|
* @return the byte array form of this attribute.
|
||||||
|
*/
|
||||||
|
protected ByteVector write(final ClassWriter cw, final byte[] code,
|
||||||
|
final int len, final int maxStack, final int maxLocals) {
|
||||||
|
ByteVector v = new ByteVector();
|
||||||
|
v.data = value;
|
||||||
|
v.length = value.length;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the length of the attribute list that begins with this attribute.
|
||||||
|
*
|
||||||
|
* @return the length of the attribute list that begins with this attribute.
|
||||||
|
*/
|
||||||
|
final int getCount() {
|
||||||
|
int count = 0;
|
||||||
|
Attribute attr = this;
|
||||||
|
while (attr != null) {
|
||||||
|
count += 1;
|
||||||
|
attr = attr.next;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of all the attributes in this attribute list.
|
||||||
|
*
|
||||||
|
* @param cw
|
||||||
|
* the class writer to be used to convert the attributes into
|
||||||
|
* byte arrays, with the {@link #write write} method.
|
||||||
|
* @param code
|
||||||
|
* the bytecode of the method corresponding to these code
|
||||||
|
* attributes, or <tt>null</tt> if these attributes are not code
|
||||||
|
* attributes.
|
||||||
|
* @param len
|
||||||
|
* the length of the bytecode of the method corresponding to
|
||||||
|
* these code attributes, or <tt>null</tt> if these attributes
|
||||||
|
* are not code attributes.
|
||||||
|
* @param maxStack
|
||||||
|
* the maximum stack size of the method corresponding to these
|
||||||
|
* code attributes, or -1 if these attributes are not code
|
||||||
|
* attributes.
|
||||||
|
* @param maxLocals
|
||||||
|
* the maximum number of local variables of the method
|
||||||
|
* corresponding to these code attributes, or -1 if these
|
||||||
|
* attributes are not code attributes.
|
||||||
|
* @return the size of all the attributes in this attribute list. This size
|
||||||
|
* includes the size of the attribute headers.
|
||||||
|
*/
|
||||||
|
final int getSize(final ClassWriter cw, final byte[] code, final int len,
|
||||||
|
final int maxStack, final int maxLocals) {
|
||||||
|
Attribute attr = this;
|
||||||
|
int size = 0;
|
||||||
|
while (attr != null) {
|
||||||
|
cw.newUTF8(attr.type);
|
||||||
|
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
|
||||||
|
attr = attr.next;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes all the attributes of this attribute list in the given byte
|
||||||
|
* vector.
|
||||||
|
*
|
||||||
|
* @param cw
|
||||||
|
* the class writer to be used to convert the attributes into
|
||||||
|
* byte arrays, with the {@link #write write} method.
|
||||||
|
* @param code
|
||||||
|
* the bytecode of the method corresponding to these code
|
||||||
|
* attributes, or <tt>null</tt> if these attributes are not code
|
||||||
|
* attributes.
|
||||||
|
* @param len
|
||||||
|
* the length of the bytecode of the method corresponding to
|
||||||
|
* these code attributes, or <tt>null</tt> if these attributes
|
||||||
|
* are not code attributes.
|
||||||
|
* @param maxStack
|
||||||
|
* the maximum stack size of the method corresponding to these
|
||||||
|
* code attributes, or -1 if these attributes are not code
|
||||||
|
* attributes.
|
||||||
|
* @param maxLocals
|
||||||
|
* the maximum number of local variables of the method
|
||||||
|
* corresponding to these code attributes, or -1 if these
|
||||||
|
* attributes are not code attributes.
|
||||||
|
* @param out
|
||||||
|
* where the attributes must be written.
|
||||||
|
*/
|
||||||
|
final void put(final ClassWriter cw, final byte[] code, final int len,
|
||||||
|
final int maxStack, final int maxLocals, final ByteVector out) {
|
||||||
|
Attribute attr = this;
|
||||||
|
while (attr != null) {
|
||||||
|
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
|
||||||
|
out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
|
||||||
|
out.putByteArray(b.data, 0, b.length);
|
||||||
|
attr = attr.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely removed.
|
||||||
|
//see also changes in ClassReader.accept.
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class NestMembers extends Attribute {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public NestMembers() {
|
||||||
|
super("NestMembers");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bytes;
|
||||||
|
String[] classes;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||||
|
int offset = off;
|
||||||
|
NestMembers a = new NestMembers();
|
||||||
|
int size = cr.readShort(off);
|
||||||
|
a.classes = new String[size];
|
||||||
|
off += 2;
|
||||||
|
for (int i = 0; i < size ; i++) {
|
||||||
|
a.classes[i] = cr.readClass(off, buf);
|
||||||
|
off += 2;
|
||||||
|
}
|
||||||
|
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||||
|
ByteVector v = new ByteVector(bytes.length);
|
||||||
|
v.putShort(classes.length);
|
||||||
|
for (String s : classes) {
|
||||||
|
v.putShort(cw.newClass(s));
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class NestHost extends Attribute {
|
||||||
|
|
||||||
|
byte[] bytes;
|
||||||
|
String clazz;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public NestHost() {
|
||||||
|
super("NestHost");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||||
|
int offset = off;
|
||||||
|
NestHost a = new NestHost();
|
||||||
|
a.clazz = cr.readClass(off, buf);
|
||||||
|
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||||
|
ByteVector v = new ByteVector(bytes.length);
|
||||||
|
v.putShort(cw.newClass(clazz));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {
|
||||||
|
new NestMembers(),
|
||||||
|
new NestHost()
|
||||||
|
};
|
||||||
|
}
|
||||||
368
src/main/java/org/redkale/asm/ByteVector.java
Normal file
368
src/main/java/org/redkale/asm/ByteVector.java
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dynamically extensible vector of bytes. This class is roughly equivalent to
|
||||||
|
* a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public class ByteVector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content of this vector.
|
||||||
|
*/
|
||||||
|
byte[] data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actual number of bytes in this vector.
|
||||||
|
*/
|
||||||
|
int length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link ByteVector ByteVector} with a default initial
|
||||||
|
* size.
|
||||||
|
*/
|
||||||
|
public ByteVector() {
|
||||||
|
data = new byte[64];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link ByteVector ByteVector} with the given initial
|
||||||
|
* size.
|
||||||
|
*
|
||||||
|
* @param initialSize
|
||||||
|
* the initial size of the byte vector to be constructed.
|
||||||
|
*/
|
||||||
|
public ByteVector(final int initialSize) {
|
||||||
|
data = new byte[initialSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a byte into this byte vector. The byte vector is automatically
|
||||||
|
* enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* a byte.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
public ByteVector putByte(final int b) {
|
||||||
|
int length = this.length;
|
||||||
|
if (length + 1 > data.length) {
|
||||||
|
enlarge(1);
|
||||||
|
}
|
||||||
|
data[length++] = (byte) b;
|
||||||
|
this.length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts two bytes into this byte vector. The byte vector is automatically
|
||||||
|
* enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param b1
|
||||||
|
* a byte.
|
||||||
|
* @param b2
|
||||||
|
* another byte.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
ByteVector put11(final int b1, final int b2) {
|
||||||
|
int length = this.length;
|
||||||
|
if (length + 2 > data.length) {
|
||||||
|
enlarge(2);
|
||||||
|
}
|
||||||
|
byte[] data = this.data;
|
||||||
|
data[length++] = (byte) b1;
|
||||||
|
data[length++] = (byte) b2;
|
||||||
|
this.length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a short into this byte vector. The byte vector is automatically
|
||||||
|
* enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* a short.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
public ByteVector putShort(final int s) {
|
||||||
|
int length = this.length;
|
||||||
|
if (length + 2 > data.length) {
|
||||||
|
enlarge(2);
|
||||||
|
}
|
||||||
|
byte[] data = this.data;
|
||||||
|
data[length++] = (byte) (s >>> 8);
|
||||||
|
data[length++] = (byte) s;
|
||||||
|
this.length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a byte and a short into this byte vector. The byte vector is
|
||||||
|
* automatically enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* a byte.
|
||||||
|
* @param s
|
||||||
|
* a short.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
ByteVector put12(final int b, final int s) {
|
||||||
|
int length = this.length;
|
||||||
|
if (length + 3 > data.length) {
|
||||||
|
enlarge(3);
|
||||||
|
}
|
||||||
|
byte[] data = this.data;
|
||||||
|
data[length++] = (byte) b;
|
||||||
|
data[length++] = (byte) (s >>> 8);
|
||||||
|
data[length++] = (byte) s;
|
||||||
|
this.length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts an int into this byte vector. The byte vector is automatically
|
||||||
|
* enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param i
|
||||||
|
* an int.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
public ByteVector putInt(final int i) {
|
||||||
|
int length = this.length;
|
||||||
|
if (length + 4 > data.length) {
|
||||||
|
enlarge(4);
|
||||||
|
}
|
||||||
|
byte[] data = this.data;
|
||||||
|
data[length++] = (byte) (i >>> 24);
|
||||||
|
data[length++] = (byte) (i >>> 16);
|
||||||
|
data[length++] = (byte) (i >>> 8);
|
||||||
|
data[length++] = (byte) i;
|
||||||
|
this.length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a long into this byte vector. The byte vector is automatically
|
||||||
|
* enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param l
|
||||||
|
* a long.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
public ByteVector putLong(final long l) {
|
||||||
|
int length = this.length;
|
||||||
|
if (length + 8 > data.length) {
|
||||||
|
enlarge(8);
|
||||||
|
}
|
||||||
|
byte[] data = this.data;
|
||||||
|
int i = (int) (l >>> 32);
|
||||||
|
data[length++] = (byte) (i >>> 24);
|
||||||
|
data[length++] = (byte) (i >>> 16);
|
||||||
|
data[length++] = (byte) (i >>> 8);
|
||||||
|
data[length++] = (byte) i;
|
||||||
|
i = (int) l;
|
||||||
|
data[length++] = (byte) (i >>> 24);
|
||||||
|
data[length++] = (byte) (i >>> 16);
|
||||||
|
data[length++] = (byte) (i >>> 8);
|
||||||
|
data[length++] = (byte) i;
|
||||||
|
this.length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts an UTF8 string into this byte vector. The byte vector is
|
||||||
|
* automatically enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* a String whose UTF8 encoded length must be less than 65536.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
public ByteVector putUTF8(final String s) {
|
||||||
|
int charLength = s.length();
|
||||||
|
if (charLength > 65535) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
int len = length;
|
||||||
|
if (len + 2 + charLength > data.length) {
|
||||||
|
enlarge(2 + charLength);
|
||||||
|
}
|
||||||
|
byte[] data = this.data;
|
||||||
|
// optimistic algorithm: instead of computing the byte length and then
|
||||||
|
// serializing the string (which requires two loops), we assume the byte
|
||||||
|
// length is equal to char length (which is the most frequent case), and
|
||||||
|
// we start serializing the string right away. During the serialization,
|
||||||
|
// if we find that this assumption is wrong, we continue with the
|
||||||
|
// general method.
|
||||||
|
data[len++] = (byte) (charLength >>> 8);
|
||||||
|
data[len++] = (byte) charLength;
|
||||||
|
for (int i = 0; i < charLength; ++i) {
|
||||||
|
char c = s.charAt(i);
|
||||||
|
if (c >= '\001' && c <= '\177') {
|
||||||
|
data[len++] = (byte) c;
|
||||||
|
} else {
|
||||||
|
length = len;
|
||||||
|
return encodeUTF8(s, i, 65535);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
length = len;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts an UTF8 string into this byte vector. The byte vector is
|
||||||
|
* automatically enlarged if necessary. The string length is encoded in two
|
||||||
|
* bytes before the encoded characters, if there is space for that (i.e. if
|
||||||
|
* this.length - i - 2 >= 0).
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* the String to encode.
|
||||||
|
* @param i
|
||||||
|
* the index of the first character to encode. The previous
|
||||||
|
* characters are supposed to have already been encoded, using
|
||||||
|
* only one byte per character.
|
||||||
|
* @param maxByteLength
|
||||||
|
* the maximum byte length of the encoded string, including the
|
||||||
|
* already encoded characters.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
|
||||||
|
int charLength = s.length();
|
||||||
|
int byteLength = i;
|
||||||
|
char c;
|
||||||
|
for (int j = i; j < charLength; ++j) {
|
||||||
|
c = s.charAt(j);
|
||||||
|
if (c >= '\001' && c <= '\177') {
|
||||||
|
byteLength++;
|
||||||
|
} else if (c > '\u07FF') {
|
||||||
|
byteLength += 3;
|
||||||
|
} else {
|
||||||
|
byteLength += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (byteLength > maxByteLength) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
int start = length - i - 2;
|
||||||
|
if (start >= 0) {
|
||||||
|
data[start] = (byte) (byteLength >>> 8);
|
||||||
|
data[start + 1] = (byte) byteLength;
|
||||||
|
}
|
||||||
|
if (length + byteLength - i > data.length) {
|
||||||
|
enlarge(byteLength - i);
|
||||||
|
}
|
||||||
|
int len = length;
|
||||||
|
for (int j = i; j < charLength; ++j) {
|
||||||
|
c = s.charAt(j);
|
||||||
|
if (c >= '\001' && c <= '\177') {
|
||||||
|
data[len++] = (byte) c;
|
||||||
|
} else if (c > '\u07FF') {
|
||||||
|
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
|
||||||
|
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
|
||||||
|
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||||
|
} else {
|
||||||
|
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
|
||||||
|
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
length = len;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts an array of bytes into this byte vector. The byte vector is
|
||||||
|
* automatically enlarged if necessary.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
|
||||||
|
* null bytes into this byte vector.
|
||||||
|
* @param off
|
||||||
|
* index of the fist byte of b that must be copied.
|
||||||
|
* @param len
|
||||||
|
* number of bytes of b that must be copied.
|
||||||
|
* @return this byte vector.
|
||||||
|
*/
|
||||||
|
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
|
||||||
|
if (length + len > data.length) {
|
||||||
|
enlarge(len);
|
||||||
|
}
|
||||||
|
if (b != null) {
|
||||||
|
System.arraycopy(b, off, data, length, len);
|
||||||
|
}
|
||||||
|
length += len;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enlarge this byte vector so that it can receive n more bytes.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* number of additional bytes that this byte vector should be
|
||||||
|
* able to receive.
|
||||||
|
*/
|
||||||
|
private void enlarge(final int size) {
|
||||||
|
int length1 = 2 * data.length;
|
||||||
|
int length2 = length + size;
|
||||||
|
byte[] newData = new byte[length1 > length2 ? length1 : length2];
|
||||||
|
System.arraycopy(data, 0, newData, 0, length);
|
||||||
|
data = newData;
|
||||||
|
}
|
||||||
|
}
|
||||||
2789
src/main/java/org/redkale/asm/ClassReader.java
Normal file
2789
src/main/java/org/redkale/asm/ClassReader.java
Normal file
File diff suppressed because it is too large
Load Diff
365
src/main/java/org/redkale/asm/ClassVisitor.java
Normal file
365
src/main/java/org/redkale/asm/ClassVisitor.java
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A visitor to visit a Java class. The methods of this class must be called in
|
||||||
|
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
|
||||||
|
* <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
|
||||||
|
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
|
||||||
|
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
|
||||||
|
* <tt>visitEnd</tt>.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public abstract class ClassVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ASM API version implemented by this visitor. The value of this field
|
||||||
|
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
protected final int api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class visitor to which this visitor must delegate method calls. May
|
||||||
|
* be null.
|
||||||
|
*/
|
||||||
|
protected ClassVisitor cv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link ClassVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
public ClassVisitor(final int api) {
|
||||||
|
this(api, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link ClassVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
* @param cv
|
||||||
|
* the class visitor to which this visitor must delegate method
|
||||||
|
* calls. May be null.
|
||||||
|
*/
|
||||||
|
public ClassVisitor(final int api, final ClassVisitor cv) {
|
||||||
|
this.api = api;
|
||||||
|
this.cv = cv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the header of the class.
|
||||||
|
*
|
||||||
|
* @param version
|
||||||
|
* the class version.
|
||||||
|
* @param access
|
||||||
|
* the class's access flags (see {@link Opcodes}). This parameter
|
||||||
|
* also indicates if the class is deprecated.
|
||||||
|
* @param name
|
||||||
|
* the internal name of the class (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}).
|
||||||
|
* @param signature
|
||||||
|
* the signature of this class. May be <tt>null</tt> if the class
|
||||||
|
* is not a generic one, and does not extend or implement generic
|
||||||
|
* classes or interfaces.
|
||||||
|
* @param superName
|
||||||
|
* the internal of name of the super class (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}). For
|
||||||
|
* interfaces, the super class is {@link Object}. May be
|
||||||
|
* <tt>null</tt>, but only for the {@link Object} class.
|
||||||
|
* @param interfaces
|
||||||
|
* the internal names of the class's interfaces (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}). May be
|
||||||
|
* <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
public void visit(int version, int access, String name, String signature,
|
||||||
|
String superName, String[] interfaces) {
|
||||||
|
if (cv != null) {
|
||||||
|
cv.visit(version, access, name, signature, superName, interfaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the source of the class.
|
||||||
|
*
|
||||||
|
* @param source
|
||||||
|
* the name of the source file from which the class was compiled.
|
||||||
|
* May be <tt>null</tt>.
|
||||||
|
* @param debug
|
||||||
|
* additional debug information to compute the correspondance
|
||||||
|
* between source and compiled elements of the class. May be
|
||||||
|
* <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
public void visitSource(String source, String debug) {
|
||||||
|
if (cv != null) {
|
||||||
|
cv.visitSource(source, debug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit the module corresponding to the class.
|
||||||
|
* @param name
|
||||||
|
* module name
|
||||||
|
* @param access
|
||||||
|
* module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
|
||||||
|
* and {@code ACC_MANDATED}.
|
||||||
|
* @param version
|
||||||
|
* module version or null.
|
||||||
|
* @return a visitor to visit the module values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this module.
|
||||||
|
*/
|
||||||
|
public ModuleVisitor visitModule(String name, int access, String version) {
|
||||||
|
if (api < Opcodes.ASM6) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
if (cv != null) {
|
||||||
|
return cv.visitModule(name, access, version);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the enclosing class of the class. This method must be called only
|
||||||
|
* if the class has an enclosing class.
|
||||||
|
*
|
||||||
|
* @param owner
|
||||||
|
* internal name of the enclosing class of the class.
|
||||||
|
* @param name
|
||||||
|
* the name of the method that contains the class, or
|
||||||
|
* <tt>null</tt> if the class is not enclosed in a method of its
|
||||||
|
* enclosing class.
|
||||||
|
* @param desc
|
||||||
|
* the descriptor of the method that contains the class, or
|
||||||
|
* <tt>null</tt> if the class is not enclosed in a method of its
|
||||||
|
* enclosing class.
|
||||||
|
*/
|
||||||
|
public void visitOuterClass(String owner, String name, String desc) {
|
||||||
|
if (cv != null) {
|
||||||
|
cv.visitOuterClass(owner, name, desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation of the class.
|
||||||
|
*
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||||
|
if (cv != null) {
|
||||||
|
return cv.visitAnnotation(desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation on a type in the class signature.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* a reference to the annotated type. The sort of this type
|
||||||
|
* reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
|
||||||
|
* CLASS_TYPE_PARAMETER},
|
||||||
|
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
|
||||||
|
* CLASS_TYPE_PARAMETER_BOUND} or
|
||||||
|
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
|
||||||
|
* {@link TypeReference}.
|
||||||
|
* @param typePath
|
||||||
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
|
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||||
|
TypePath typePath, String desc, boolean visible) {
|
||||||
|
if (cv != null) {
|
||||||
|
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a non standard attribute of the class.
|
||||||
|
*
|
||||||
|
* @param attr
|
||||||
|
* an attribute.
|
||||||
|
*/
|
||||||
|
public void visitAttribute(Attribute attr) {
|
||||||
|
if (cv != null) {
|
||||||
|
cv.visitAttribute(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits information about an inner class. This inner class is not
|
||||||
|
* necessarily a member of the class being visited.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the internal name of an inner class (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}).
|
||||||
|
* @param outerName
|
||||||
|
* the internal name of the class to which the inner class
|
||||||
|
* belongs (see {@link Type#getInternalName() getInternalName}).
|
||||||
|
* May be <tt>null</tt> for not member classes.
|
||||||
|
* @param innerName
|
||||||
|
* the (simple) name of the inner class inside its enclosing
|
||||||
|
* class. May be <tt>null</tt> for anonymous inner classes.
|
||||||
|
* @param access
|
||||||
|
* the access flags of the inner class as originally declared in
|
||||||
|
* the enclosing class.
|
||||||
|
*/
|
||||||
|
public void visitInnerClass(String name, String outerName,
|
||||||
|
String innerName, int access) {
|
||||||
|
if (cv != null) {
|
||||||
|
cv.visitInnerClass(name, outerName, innerName, access);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a field of the class.
|
||||||
|
*
|
||||||
|
* @param access
|
||||||
|
* the field's access flags (see {@link Opcodes}). This parameter
|
||||||
|
* also indicates if the field is synthetic and/or deprecated.
|
||||||
|
* @param name
|
||||||
|
* the field's name.
|
||||||
|
* @param desc
|
||||||
|
* the field's descriptor (see {@link Type Type}).
|
||||||
|
* @param signature
|
||||||
|
* the field's signature. May be <tt>null</tt> if the field's
|
||||||
|
* type does not use generic types.
|
||||||
|
* @param value
|
||||||
|
* the field's initial value. This parameter, which may be
|
||||||
|
* <tt>null</tt> if the field does not have an initial value,
|
||||||
|
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
|
||||||
|
* {@link Double} or a {@link String} (for <tt>int</tt>,
|
||||||
|
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
|
||||||
|
* respectively). <i>This parameter is only used for static
|
||||||
|
* fields</i>. Its value is ignored for non static fields, which
|
||||||
|
* must be initialized through bytecode instructions in
|
||||||
|
* constructors or methods.
|
||||||
|
* @return a visitor to visit field annotations and attributes, or
|
||||||
|
* <tt>null</tt> if this class visitor is not interested in visiting
|
||||||
|
* these annotations and attributes.
|
||||||
|
*/
|
||||||
|
public FieldVisitor visitField(int access, String name, String desc,
|
||||||
|
String signature, Object value) {
|
||||||
|
if (cv != null) {
|
||||||
|
return cv.visitField(access, name, desc, signature, value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a method of the class. This method <i>must</i> return a new
|
||||||
|
* {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
|
||||||
|
* i.e., it should not return a previously returned visitor.
|
||||||
|
*
|
||||||
|
* @param access
|
||||||
|
* the method's access flags (see {@link Opcodes}). This
|
||||||
|
* parameter also indicates if the method is synthetic and/or
|
||||||
|
* deprecated.
|
||||||
|
* @param name
|
||||||
|
* the method's name.
|
||||||
|
* @param desc
|
||||||
|
* the method's descriptor (see {@link Type Type}).
|
||||||
|
* @param signature
|
||||||
|
* the method's signature. May be <tt>null</tt> if the method
|
||||||
|
* parameters, return type and exceptions do not use generic
|
||||||
|
* types.
|
||||||
|
* @param exceptions
|
||||||
|
* the internal names of the method's exception classes (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}). May be
|
||||||
|
* <tt>null</tt>.
|
||||||
|
* @return an object to visit the byte code of the method, or <tt>null</tt>
|
||||||
|
* if this class visitor is not interested in visiting the code of
|
||||||
|
* this method.
|
||||||
|
*/
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String desc,
|
||||||
|
String signature, String[] exceptions) {
|
||||||
|
if (cv != null) {
|
||||||
|
return cv.visitMethod(access, name, desc, signature, exceptions);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the end of the class. This method, which is the last one to be
|
||||||
|
* called, is used to inform the visitor that all the fields and methods of
|
||||||
|
* the class have been visited.
|
||||||
|
*/
|
||||||
|
public void visitEnd() {
|
||||||
|
if (cv != null) {
|
||||||
|
cv.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1848
src/main/java/org/redkale/asm/ClassWriter.java
Normal file
1848
src/main/java/org/redkale/asm/ClassWriter.java
Normal file
File diff suppressed because it is too large
Load Diff
174
src/main/java/org/redkale/asm/Context.java
Normal file
174
src/main/java/org/redkale/asm/Context.java
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a class being parsed in a {@link ClassReader}.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
class Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prototypes of the attributes that must be parsed for this class.
|
||||||
|
*/
|
||||||
|
Attribute[] attrs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ClassReader} option flags for the parsing of this class.
|
||||||
|
*/
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer used to read strings.
|
||||||
|
*/
|
||||||
|
char[] buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start index of each bootstrap method.
|
||||||
|
*/
|
||||||
|
int[] bootstrapMethods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The access flags of the method currently being parsed.
|
||||||
|
*/
|
||||||
|
int access;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the method currently being parsed.
|
||||||
|
*/
|
||||||
|
String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The descriptor of the method currently being parsed.
|
||||||
|
*/
|
||||||
|
String desc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label objects, indexed by bytecode offset, of the method currently
|
||||||
|
* being parsed (only bytecode offsets for which a label is needed have a
|
||||||
|
* non null associated Label object).
|
||||||
|
*/
|
||||||
|
Label[] labels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target of the type annotation currently being parsed.
|
||||||
|
*/
|
||||||
|
int typeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path of the type annotation currently being parsed.
|
||||||
|
*/
|
||||||
|
TypePath typePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset of the latest stack map frame that has been parsed.
|
||||||
|
*/
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The labels corresponding to the start of the local variable ranges in the
|
||||||
|
* local variable type annotation currently being parsed.
|
||||||
|
*/
|
||||||
|
Label[] start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The labels corresponding to the end of the local variable ranges in the
|
||||||
|
* local variable type annotation currently being parsed.
|
||||||
|
*/
|
||||||
|
Label[] end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The local variable indices for each local variable range in the local
|
||||||
|
* variable type annotation currently being parsed.
|
||||||
|
*/
|
||||||
|
int[] index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoding of the latest stack map frame that has been parsed.
|
||||||
|
*/
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of locals in the latest stack map frame that has been parsed.
|
||||||
|
*/
|
||||||
|
int localCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number locals in the latest stack map frame that has been parsed,
|
||||||
|
* minus the number of locals in the previous frame.
|
||||||
|
*/
|
||||||
|
int localDiff;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The local values of the latest stack map frame that has been parsed.
|
||||||
|
*/
|
||||||
|
Object[] local;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stack size of the latest stack map frame that has been parsed.
|
||||||
|
*/
|
||||||
|
int stackCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stack values of the latest stack map frame that has been parsed.
|
||||||
|
*/
|
||||||
|
Object[] stack;
|
||||||
|
}
|
||||||
85
src/main/java/org/redkale/asm/CurrentFrame.java
Normal file
85
src/main/java/org/redkale/asm/CurrentFrame.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the input stack map frame at the "current" instruction of a
|
||||||
|
* method. This is implemented as a Frame subclass for a "basic block"
|
||||||
|
* containing only one instruction.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
class CurrentFrame extends Frame {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this CurrentFrame to the input stack map frame of the next "current"
|
||||||
|
* instruction, i.e. the instruction just after the given one. It is assumed
|
||||||
|
* that the value of this object when this method is called is the stack map
|
||||||
|
* frame status just before the given instruction is executed.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void execute(int opcode, int arg, ClassWriter cw, Item item) {
|
||||||
|
super.execute(opcode, arg, cw, item);
|
||||||
|
Frame successor = new Frame();
|
||||||
|
merge(cw, successor, 0);
|
||||||
|
set(successor);
|
||||||
|
owner.inputStackTop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/main/java/org/redkale/asm/Edge.java
Normal file
104
src/main/java/org/redkale/asm/Edge.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An edge in the control flow graph of a method body. See {@link Label Label}.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
class Edge {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes a normal control flow graph edge.
|
||||||
|
*/
|
||||||
|
static final int NORMAL = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes a control flow graph edge corresponding to an exception handler.
|
||||||
|
* More precisely any {@link Edge} whose {@link #info} is strictly positive
|
||||||
|
* corresponds to an exception handler. The actual value of {@link #info} is
|
||||||
|
* the index, in the {@link ClassWriter} type table, of the exception that
|
||||||
|
* is catched.
|
||||||
|
*/
|
||||||
|
static final int EXCEPTION = 0x7FFFFFFF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about this control flow graph edge. If
|
||||||
|
* {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
|
||||||
|
* stack size in the basic block from which this edge originates. This size
|
||||||
|
* is equal to the stack size at the "jump" instruction to which this edge
|
||||||
|
* corresponds, relatively to the stack size at the beginning of the
|
||||||
|
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
|
||||||
|
* this field is the kind of this control flow graph edge (i.e. NORMAL or
|
||||||
|
* EXCEPTION).
|
||||||
|
*/
|
||||||
|
int info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The successor block of the basic block from which this edge originates.
|
||||||
|
*/
|
||||||
|
Label successor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next edge in the list of successors of the originating basic block.
|
||||||
|
* See {@link Label#successors successors}.
|
||||||
|
*/
|
||||||
|
Edge next;
|
||||||
|
}
|
||||||
173
src/main/java/org/redkale/asm/FieldVisitor.java
Normal file
173
src/main/java/org/redkale/asm/FieldVisitor.java
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A visitor to visit a Java field. The methods of this class must be called in
|
||||||
|
* the following order: ( <tt>visitAnnotation</tt> |
|
||||||
|
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public abstract class FieldVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ASM API version implemented by this visitor. The value of this field
|
||||||
|
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
protected final int api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The field visitor to which this visitor must delegate method calls. May
|
||||||
|
* be null.
|
||||||
|
*/
|
||||||
|
protected FieldVisitor fv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link FieldVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
public FieldVisitor(final int api) {
|
||||||
|
this(api, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link FieldVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
* @param fv
|
||||||
|
* the field visitor to which this visitor must delegate method
|
||||||
|
* calls. May be null.
|
||||||
|
*/
|
||||||
|
public FieldVisitor(final int api, final FieldVisitor fv) {
|
||||||
|
this.api = api;
|
||||||
|
this.fv = fv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation of the field.
|
||||||
|
*
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||||
|
if (fv != null) {
|
||||||
|
return fv.visitAnnotation(desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation on the type of the field.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* a reference to the annotated type. The sort of this type
|
||||||
|
* reference must be {@link TypeReference#FIELD FIELD}. See
|
||||||
|
* {@link TypeReference}.
|
||||||
|
* @param typePath
|
||||||
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
|
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||||
|
TypePath typePath, String desc, boolean visible) {
|
||||||
|
if (fv != null) {
|
||||||
|
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a non standard attribute of the field.
|
||||||
|
*
|
||||||
|
* @param attr
|
||||||
|
* an attribute.
|
||||||
|
*/
|
||||||
|
public void visitAttribute(Attribute attr) {
|
||||||
|
if (fv != null) {
|
||||||
|
fv.visitAttribute(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the end of the field. This method, which is the last one to be
|
||||||
|
* called, is used to inform the visitor that all the annotations and
|
||||||
|
* attributes of the field have been visited.
|
||||||
|
*/
|
||||||
|
public void visitEnd() {
|
||||||
|
if (fv != null) {
|
||||||
|
fv.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
352
src/main/java/org/redkale/asm/FieldWriter.java
Normal file
352
src/main/java/org/redkale/asm/FieldWriter.java
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link FieldVisitor} that generates Java fields in bytecode form.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
final class FieldWriter extends FieldVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class writer to which this field must be added.
|
||||||
|
*/
|
||||||
|
private final ClassWriter cw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access flags of this field.
|
||||||
|
*/
|
||||||
|
private final int access;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the constant pool item that contains the name of this
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
private final int name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the constant pool item that contains the descriptor of this
|
||||||
|
* field.
|
||||||
|
*/
|
||||||
|
private final int desc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the constant pool item that contains the signature of this
|
||||||
|
* field.
|
||||||
|
*/
|
||||||
|
private int signature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the constant pool item that contains the constant value of
|
||||||
|
* this field.
|
||||||
|
*/
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The runtime visible annotations of this field. May be <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
private AnnotationWriter anns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The runtime invisible annotations of this field. May be <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
private AnnotationWriter ianns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The runtime visible type annotations of this field. May be <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
private AnnotationWriter tanns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The runtime invisible type annotations of this field. May be
|
||||||
|
* <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
private AnnotationWriter itanns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The non standard attributes of this field. May be <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
private Attribute attrs;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constructor
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link FieldWriter}.
|
||||||
|
*
|
||||||
|
* @param cw
|
||||||
|
* the class writer to which this field must be added.
|
||||||
|
* @param access
|
||||||
|
* the field's access flags (see {@link Opcodes}).
|
||||||
|
* @param name
|
||||||
|
* the field's name.
|
||||||
|
* @param desc
|
||||||
|
* the field's descriptor (see {@link Type}).
|
||||||
|
* @param signature
|
||||||
|
* the field's signature. May be <tt>null</tt>.
|
||||||
|
* @param value
|
||||||
|
* the field's constant value. May be <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
FieldWriter(final ClassWriter cw, final int access, final String name,
|
||||||
|
final String desc, final String signature, final Object value) {
|
||||||
|
super(Opcodes.ASM6);
|
||||||
|
if (cw.firstField == null) {
|
||||||
|
cw.firstField = this;
|
||||||
|
} else {
|
||||||
|
cw.lastField.fv = this;
|
||||||
|
}
|
||||||
|
cw.lastField = this;
|
||||||
|
this.cw = cw;
|
||||||
|
this.access = access;
|
||||||
|
this.name = cw.newUTF8(name);
|
||||||
|
this.desc = cw.newUTF8(desc);
|
||||||
|
if (signature != null) {
|
||||||
|
this.signature = cw.newUTF8(signature);
|
||||||
|
}
|
||||||
|
if (value != null) {
|
||||||
|
this.value = cw.newConstItem(value).index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Implementation of the FieldVisitor abstract class
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationVisitor visitAnnotation(final String desc,
|
||||||
|
final boolean visible) {
|
||||||
|
ByteVector bv = new ByteVector();
|
||||||
|
// write type, and reserve space for values count
|
||||||
|
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||||
|
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
|
||||||
|
if (visible) {
|
||||||
|
aw.next = anns;
|
||||||
|
anns = aw;
|
||||||
|
} else {
|
||||||
|
aw.next = ianns;
|
||||||
|
ianns = aw;
|
||||||
|
}
|
||||||
|
return aw;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
|
||||||
|
final TypePath typePath, final String desc, final boolean visible) {
|
||||||
|
ByteVector bv = new ByteVector();
|
||||||
|
// write target_type and target_info
|
||||||
|
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||||
|
// write type, and reserve space for values count
|
||||||
|
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||||
|
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
|
||||||
|
bv.length - 2);
|
||||||
|
if (visible) {
|
||||||
|
aw.next = tanns;
|
||||||
|
tanns = aw;
|
||||||
|
} else {
|
||||||
|
aw.next = itanns;
|
||||||
|
itanns = aw;
|
||||||
|
}
|
||||||
|
return aw;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitAttribute(final Attribute attr) {
|
||||||
|
attr.next = attrs;
|
||||||
|
attrs = attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Utility methods
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of this field.
|
||||||
|
*
|
||||||
|
* @return the size of this field.
|
||||||
|
*/
|
||||||
|
int getSize() {
|
||||||
|
int size = 8;
|
||||||
|
if (value != 0) {
|
||||||
|
cw.newUTF8("ConstantValue");
|
||||||
|
size += 8;
|
||||||
|
}
|
||||||
|
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||||
|
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|
||||||
|
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||||
|
cw.newUTF8("Synthetic");
|
||||||
|
size += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||||
|
cw.newUTF8("Deprecated");
|
||||||
|
size += 6;
|
||||||
|
}
|
||||||
|
if (signature != 0) {
|
||||||
|
cw.newUTF8("Signature");
|
||||||
|
size += 8;
|
||||||
|
}
|
||||||
|
if (anns != null) {
|
||||||
|
cw.newUTF8("RuntimeVisibleAnnotations");
|
||||||
|
size += 8 + anns.getSize();
|
||||||
|
}
|
||||||
|
if (ianns != null) {
|
||||||
|
cw.newUTF8("RuntimeInvisibleAnnotations");
|
||||||
|
size += 8 + ianns.getSize();
|
||||||
|
}
|
||||||
|
if (tanns != null) {
|
||||||
|
cw.newUTF8("RuntimeVisibleTypeAnnotations");
|
||||||
|
size += 8 + tanns.getSize();
|
||||||
|
}
|
||||||
|
if (itanns != null) {
|
||||||
|
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||||
|
size += 8 + itanns.getSize();
|
||||||
|
}
|
||||||
|
if (attrs != null) {
|
||||||
|
size += attrs.getSize(cw, null, 0, -1, -1);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the content of this field into the given byte vector.
|
||||||
|
*
|
||||||
|
* @param out
|
||||||
|
* where the content of this field must be put.
|
||||||
|
*/
|
||||||
|
void put(final ByteVector out) {
|
||||||
|
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
|
||||||
|
int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
|
||||||
|
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
|
||||||
|
out.putShort(access & ~mask).putShort(name).putShort(desc);
|
||||||
|
int attributeCount = 0;
|
||||||
|
if (value != 0) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||||
|
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|
||||||
|
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
if (signature != 0) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
if (anns != null) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
if (ianns != null) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
if (tanns != null) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
if (itanns != null) {
|
||||||
|
++attributeCount;
|
||||||
|
}
|
||||||
|
if (attrs != null) {
|
||||||
|
attributeCount += attrs.getCount();
|
||||||
|
}
|
||||||
|
out.putShort(attributeCount);
|
||||||
|
if (value != 0) {
|
||||||
|
out.putShort(cw.newUTF8("ConstantValue"));
|
||||||
|
out.putInt(2).putShort(value);
|
||||||
|
}
|
||||||
|
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||||
|
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|
||||||
|
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||||
|
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||||
|
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
|
||||||
|
}
|
||||||
|
if (signature != 0) {
|
||||||
|
out.putShort(cw.newUTF8("Signature"));
|
||||||
|
out.putInt(2).putShort(signature);
|
||||||
|
}
|
||||||
|
if (anns != null) {
|
||||||
|
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
|
||||||
|
anns.put(out);
|
||||||
|
}
|
||||||
|
if (ianns != null) {
|
||||||
|
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
|
||||||
|
ianns.put(out);
|
||||||
|
}
|
||||||
|
if (tanns != null) {
|
||||||
|
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||||
|
tanns.put(out);
|
||||||
|
}
|
||||||
|
if (itanns != null) {
|
||||||
|
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||||
|
itanns.put(out);
|
||||||
|
}
|
||||||
|
if (attrs != null) {
|
||||||
|
attrs.put(cw, null, 0, -1, -1, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1595
src/main/java/org/redkale/asm/Frame.java
Normal file
1595
src/main/java/org/redkale/asm/Frame.java
Normal file
File diff suppressed because it is too large
Load Diff
222
src/main/java/org/redkale/asm/Handle.java
Normal file
222
src/main/java/org/redkale/asm/Handle.java
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a field or a method.
|
||||||
|
*
|
||||||
|
* @author Remi Forax
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public final class Handle {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The kind of field or method designated by this Handle. Should be
|
||||||
|
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
|
||||||
|
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||||
|
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||||
|
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
|
||||||
|
* {@link Opcodes#H_INVOKEINTERFACE}.
|
||||||
|
*/
|
||||||
|
final int tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal name of the class that owns the field or method designated
|
||||||
|
* by this handle.
|
||||||
|
*/
|
||||||
|
final String owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the field or method designated by this handle.
|
||||||
|
*/
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The descriptor of the field or method designated by this handle.
|
||||||
|
*/
|
||||||
|
final String desc;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate if the owner is an interface or not.
|
||||||
|
*/
|
||||||
|
final boolean itf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new field or method handle.
|
||||||
|
*
|
||||||
|
* @param tag
|
||||||
|
* the kind of field or method designated by this Handle. Must be
|
||||||
|
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
|
||||||
|
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||||
|
* {@link Opcodes#H_INVOKEVIRTUAL},
|
||||||
|
* {@link Opcodes#H_INVOKESTATIC},
|
||||||
|
* {@link Opcodes#H_INVOKESPECIAL},
|
||||||
|
* {@link Opcodes#H_NEWINVOKESPECIAL} or
|
||||||
|
* {@link Opcodes#H_INVOKEINTERFACE}.
|
||||||
|
* @param owner
|
||||||
|
* the internal name of the class that owns the field or method
|
||||||
|
* designated by this handle.
|
||||||
|
* @param name
|
||||||
|
* the name of the field or method designated by this handle.
|
||||||
|
* @param desc
|
||||||
|
* the descriptor of the field or method designated by this
|
||||||
|
* handle.
|
||||||
|
* @param itf
|
||||||
|
* true if the owner is an interface.
|
||||||
|
*/
|
||||||
|
public Handle(int tag, String owner, String name, String desc, boolean itf) {
|
||||||
|
this.tag = tag;
|
||||||
|
this.owner = owner;
|
||||||
|
this.name = name;
|
||||||
|
this.desc = desc;
|
||||||
|
this.itf = itf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the kind of field or method designated by this handle.
|
||||||
|
*
|
||||||
|
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
|
||||||
|
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||||
|
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||||
|
* {@link Opcodes#H_INVOKESPECIAL},
|
||||||
|
* {@link Opcodes#H_NEWINVOKESPECIAL} or
|
||||||
|
* {@link Opcodes#H_INVOKEINTERFACE}.
|
||||||
|
*/
|
||||||
|
public int getTag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the internal name of the class that owns the field or method
|
||||||
|
* designated by this handle.
|
||||||
|
*
|
||||||
|
* @return the internal name of the class that owns the field or method
|
||||||
|
* designated by this handle.
|
||||||
|
*/
|
||||||
|
public String getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the field or method designated by this handle.
|
||||||
|
*
|
||||||
|
* @return the name of the field or method designated by this handle.
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the descriptor of the field or method designated by this handle.
|
||||||
|
*
|
||||||
|
* @return the descriptor of the field or method designated by this handle.
|
||||||
|
*/
|
||||||
|
public String getDesc() {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the owner of the field or method designated
|
||||||
|
* by this handle is an interface.
|
||||||
|
*
|
||||||
|
* @return true if the owner of the field or method designated
|
||||||
|
* by this handle is an interface.
|
||||||
|
*/
|
||||||
|
public boolean isInterface() {
|
||||||
|
return itf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Handle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Handle h = (Handle) obj;
|
||||||
|
return tag == h.tag && itf == h.itf && owner.equals(h.owner)
|
||||||
|
&& name.equals(h.name) && desc.equals(h.desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the textual representation of this handle. The textual
|
||||||
|
* representation is:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* for a reference to a class:
|
||||||
|
* owner '.' name desc ' ' '(' tag ')'
|
||||||
|
* for a reference to an interface:
|
||||||
|
* owner '.' name desc ' ' '(' tag ' ' itf ')'
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* . As this format is unambiguous, it can be parsed if necessary.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
150
src/main/java/org/redkale/asm/Handler.java
Normal file
150
src/main/java/org/redkale/asm/Handler.java
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about an exception handler block.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
class Handler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beginning of the exception handler's scope (inclusive).
|
||||||
|
*/
|
||||||
|
Label start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of the exception handler's scope (exclusive).
|
||||||
|
*/
|
||||||
|
Label end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beginning of the exception handler's code.
|
||||||
|
*/
|
||||||
|
Label handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal name of the type of exceptions handled by this handler, or
|
||||||
|
* <tt>null</tt> to catch any exceptions.
|
||||||
|
*/
|
||||||
|
String desc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant pool index of the internal name of the type of exceptions
|
||||||
|
* handled by this handler, or 0 to catch any exceptions.
|
||||||
|
*/
|
||||||
|
int type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next exception handler block info.
|
||||||
|
*/
|
||||||
|
Handler next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the range between start and end from the given exception
|
||||||
|
* handlers.
|
||||||
|
*
|
||||||
|
* @param h
|
||||||
|
* an exception handler list.
|
||||||
|
* @param start
|
||||||
|
* the start of the range to be removed.
|
||||||
|
* @param end
|
||||||
|
* the end of the range to be removed. Maybe null.
|
||||||
|
* @return the exception handler list with the start-end range removed.
|
||||||
|
*/
|
||||||
|
static Handler remove(Handler h, Label start, Label end) {
|
||||||
|
if (h == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
h.next = remove(h.next, start, end);
|
||||||
|
}
|
||||||
|
int hstart = h.start.position;
|
||||||
|
int hend = h.end.position;
|
||||||
|
int s = start.position;
|
||||||
|
int e = end == null ? Integer.MAX_VALUE : end.position;
|
||||||
|
// if [hstart,hend[ and [s,e[ intervals intersect...
|
||||||
|
if (s < hend && e > hstart) {
|
||||||
|
if (s <= hstart) {
|
||||||
|
if (e >= hend) {
|
||||||
|
// [hstart,hend[ fully included in [s,e[, h removed
|
||||||
|
h = h.next;
|
||||||
|
} else {
|
||||||
|
// [hstart,hend[ minus [s,e[ = [e,hend[
|
||||||
|
h.start = end;
|
||||||
|
}
|
||||||
|
} else if (e >= hend) {
|
||||||
|
// [hstart,hend[ minus [s,e[ = [hstart,s[
|
||||||
|
h.end = start;
|
||||||
|
} else {
|
||||||
|
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
|
||||||
|
Handler g = new Handler();
|
||||||
|
g.start = end;
|
||||||
|
g.end = h.end;
|
||||||
|
g.handler = h.handler;
|
||||||
|
g.desc = h.desc;
|
||||||
|
g.type = h.type;
|
||||||
|
g.next = h.next;
|
||||||
|
h.end = start;
|
||||||
|
h.next = g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
347
src/main/java/org/redkale/asm/Item.java
Normal file
347
src/main/java/org/redkale/asm/Item.java
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A constant pool item. Constant pool items can be created with the 'newXXX'
|
||||||
|
* methods in the {@link ClassWriter} class.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
final class Item {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of this item in the constant pool.
|
||||||
|
*/
|
||||||
|
int index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of this constant pool item. A single class is used to represent all
|
||||||
|
* constant pool item types, in order to minimize the bytecode size of this
|
||||||
|
* package. The value of this field is one of {@link ClassWriter#INT},
|
||||||
|
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
|
||||||
|
* {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
|
||||||
|
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
|
||||||
|
* {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
|
||||||
|
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
|
||||||
|
* {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
|
||||||
|
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
|
||||||
|
*
|
||||||
|
* MethodHandle constant 9 variations are stored using a range of 9 values
|
||||||
|
* from {@link ClassWriter#HANDLE_BASE} + 1 to
|
||||||
|
* {@link ClassWriter#HANDLE_BASE} + 9.
|
||||||
|
*
|
||||||
|
* Special Item types are used for Items that are stored in the ClassWriter
|
||||||
|
* {@link ClassWriter#typeTable}, instead of the constant pool, in order to
|
||||||
|
* avoid clashes with normal constant pool items in the ClassWriter constant
|
||||||
|
* pool's hash table. These special item types are
|
||||||
|
* {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
|
||||||
|
* {@link ClassWriter#TYPE_MERGED}.
|
||||||
|
*/
|
||||||
|
int type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Value of this item, for an integer item.
|
||||||
|
*/
|
||||||
|
int intVal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Value of this item, for a long item.
|
||||||
|
*/
|
||||||
|
long longVal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First part of the value of this item, for items that do not hold a
|
||||||
|
* primitive value.
|
||||||
|
*/
|
||||||
|
String strVal1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second part of the value of this item, for items that do not hold a
|
||||||
|
* primitive value.
|
||||||
|
*/
|
||||||
|
String strVal2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Third part of the value of this item, for items that do not hold a
|
||||||
|
* primitive value.
|
||||||
|
*/
|
||||||
|
String strVal3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hash code value of this constant pool item.
|
||||||
|
*/
|
||||||
|
int hashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link to another constant pool item, used for collision lists in the
|
||||||
|
* constant pool's hash table.
|
||||||
|
*/
|
||||||
|
Item next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an uninitialized {@link Item}.
|
||||||
|
*/
|
||||||
|
Item() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an uninitialized {@link Item} for constant pool element at
|
||||||
|
* given position.
|
||||||
|
*
|
||||||
|
* @param index
|
||||||
|
* index of the item to be constructed.
|
||||||
|
*/
|
||||||
|
Item(final int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a copy of the given item.
|
||||||
|
*
|
||||||
|
* @param index
|
||||||
|
* index of the item to be constructed.
|
||||||
|
* @param i
|
||||||
|
* the item that must be copied into the item to be constructed.
|
||||||
|
*/
|
||||||
|
Item(final int index, final Item i) {
|
||||||
|
this.index = index;
|
||||||
|
type = i.type;
|
||||||
|
intVal = i.intVal;
|
||||||
|
longVal = i.longVal;
|
||||||
|
strVal1 = i.strVal1;
|
||||||
|
strVal2 = i.strVal2;
|
||||||
|
strVal3 = i.strVal3;
|
||||||
|
hashCode = i.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this item to an integer item.
|
||||||
|
*
|
||||||
|
* @param intVal
|
||||||
|
* the value of this item.
|
||||||
|
*/
|
||||||
|
void set(final int intVal) {
|
||||||
|
this.type = ClassWriter.INT;
|
||||||
|
this.intVal = intVal;
|
||||||
|
this.hashCode = 0x7FFFFFFF & (type + intVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this item to a long item.
|
||||||
|
*
|
||||||
|
* @param longVal
|
||||||
|
* the value of this item.
|
||||||
|
*/
|
||||||
|
void set(final long longVal) {
|
||||||
|
this.type = ClassWriter.LONG;
|
||||||
|
this.longVal = longVal;
|
||||||
|
this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this item to a float item.
|
||||||
|
*
|
||||||
|
* @param floatVal
|
||||||
|
* the value of this item.
|
||||||
|
*/
|
||||||
|
void set(final float floatVal) {
|
||||||
|
this.type = ClassWriter.FLOAT;
|
||||||
|
this.intVal = Float.floatToRawIntBits(floatVal);
|
||||||
|
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this item to a double item.
|
||||||
|
*
|
||||||
|
* @param doubleVal
|
||||||
|
* the value of this item.
|
||||||
|
*/
|
||||||
|
void set(final double doubleVal) {
|
||||||
|
this.type = ClassWriter.DOUBLE;
|
||||||
|
this.longVal = Double.doubleToRawLongBits(doubleVal);
|
||||||
|
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this item to an item that do not hold a primitive value.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* the type of this item.
|
||||||
|
* @param strVal1
|
||||||
|
* first part of the value of this item.
|
||||||
|
* @param strVal2
|
||||||
|
* second part of the value of this item.
|
||||||
|
* @param strVal3
|
||||||
|
* third part of the value of this item.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("fallthrough")
|
||||||
|
void set(final int type, final String strVal1, final String strVal2,
|
||||||
|
final String strVal3) {
|
||||||
|
this.type = type;
|
||||||
|
this.strVal1 = strVal1;
|
||||||
|
this.strVal2 = strVal2;
|
||||||
|
this.strVal3 = strVal3;
|
||||||
|
switch (type) {
|
||||||
|
case ClassWriter.CLASS:
|
||||||
|
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
|
||||||
|
case ClassWriter.UTF8:
|
||||||
|
case ClassWriter.STR:
|
||||||
|
case ClassWriter.MTYPE:
|
||||||
|
case ClassWriter.MODULE:
|
||||||
|
case ClassWriter.PACKAGE:
|
||||||
|
case ClassWriter.TYPE_NORMAL:
|
||||||
|
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
|
||||||
|
return;
|
||||||
|
case ClassWriter.NAME_TYPE: {
|
||||||
|
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
|
||||||
|
* strVal2.hashCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ClassWriter.FIELD:
|
||||||
|
// ClassWriter.METH:
|
||||||
|
// ClassWriter.IMETH:
|
||||||
|
// ClassWriter.HANDLE_BASE + 1..9
|
||||||
|
default:
|
||||||
|
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
|
||||||
|
* strVal2.hashCode() * strVal3.hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the item to an InvokeDynamic item.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* invokedynamic's name.
|
||||||
|
* @param desc
|
||||||
|
* invokedynamic's desc.
|
||||||
|
* @param bsmIndex
|
||||||
|
* zero based index into the class attribute BootrapMethods.
|
||||||
|
*/
|
||||||
|
void set(String name, String desc, int bsmIndex) {
|
||||||
|
this.type = ClassWriter.INDY;
|
||||||
|
this.longVal = bsmIndex;
|
||||||
|
this.strVal1 = name;
|
||||||
|
this.strVal2 = desc;
|
||||||
|
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
|
||||||
|
* strVal1.hashCode() * strVal2.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the item to a BootstrapMethod item.
|
||||||
|
*
|
||||||
|
* @param position
|
||||||
|
* position in byte in the class attribute BootrapMethods.
|
||||||
|
* @param hashCode
|
||||||
|
* hashcode of the item. This hashcode is processed from the
|
||||||
|
* hashcode of the bootstrap method and the hashcode of all
|
||||||
|
* bootstrap arguments.
|
||||||
|
*/
|
||||||
|
void set(int position, int hashCode) {
|
||||||
|
this.type = ClassWriter.BSM;
|
||||||
|
this.intVal = position;
|
||||||
|
this.hashCode = hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the given item is equal to this one. <i>This method assumes
|
||||||
|
* that the two items have the same {@link #type}</i>.
|
||||||
|
*
|
||||||
|
* @param i
|
||||||
|
* the item to be compared to this one. Both items must have the
|
||||||
|
* same {@link #type}.
|
||||||
|
* @return <tt>true</tt> if the given item if equal to this one,
|
||||||
|
* <tt>false</tt> otherwise.
|
||||||
|
*/
|
||||||
|
boolean isEqualTo(final Item i) {
|
||||||
|
switch (type) {
|
||||||
|
case ClassWriter.UTF8:
|
||||||
|
case ClassWriter.STR:
|
||||||
|
case ClassWriter.CLASS:
|
||||||
|
case ClassWriter.MODULE:
|
||||||
|
case ClassWriter.PACKAGE:
|
||||||
|
case ClassWriter.MTYPE:
|
||||||
|
case ClassWriter.TYPE_NORMAL:
|
||||||
|
return i.strVal1.equals(strVal1);
|
||||||
|
case ClassWriter.TYPE_MERGED:
|
||||||
|
case ClassWriter.LONG:
|
||||||
|
case ClassWriter.DOUBLE:
|
||||||
|
return i.longVal == longVal;
|
||||||
|
case ClassWriter.INT:
|
||||||
|
case ClassWriter.FLOAT:
|
||||||
|
return i.intVal == intVal;
|
||||||
|
case ClassWriter.TYPE_UNINIT:
|
||||||
|
return i.intVal == intVal && i.strVal1.equals(strVal1);
|
||||||
|
case ClassWriter.NAME_TYPE:
|
||||||
|
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
|
||||||
|
case ClassWriter.INDY: {
|
||||||
|
return i.longVal == longVal && i.strVal1.equals(strVal1)
|
||||||
|
&& i.strVal2.equals(strVal2);
|
||||||
|
}
|
||||||
|
// case ClassWriter.FIELD:
|
||||||
|
// case ClassWriter.METH:
|
||||||
|
// case ClassWriter.IMETH:
|
||||||
|
// case ClassWriter.HANDLE_BASE + 1..9
|
||||||
|
default:
|
||||||
|
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
|
||||||
|
&& i.strVal3.equals(strVal3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
593
src/main/java/org/redkale/asm/Label.java
Normal file
593
src/main/java/org/redkale/asm/Label.java
Normal file
@@ -0,0 +1,593 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A label represents a position in the bytecode of a method. Labels are used
|
||||||
|
* for jump, goto, and switch instructions, and for try catch blocks. A label
|
||||||
|
* designates the <i>instruction</i> that is just after. Note however that there
|
||||||
|
* can be other elements between a label and the instruction it designates (such
|
||||||
|
* as other labels, stack map frames, line numbers, etc.).
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public class Label {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this label is only used for debug attributes. Such a label
|
||||||
|
* is not the start of a basic block, the target of a jump instruction, or
|
||||||
|
* an exception handler. It can be safely ignored in control flow graph
|
||||||
|
* analysis algorithms (for optimization purposes).
|
||||||
|
*/
|
||||||
|
static final int DEBUG = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the position of this label is known.
|
||||||
|
*/
|
||||||
|
static final int RESOLVED = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this label has been updated, after instruction resizing.
|
||||||
|
*/
|
||||||
|
static final int RESIZED = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this basic block has been pushed in the basic block stack.
|
||||||
|
* See {@link MethodWriter#visitMaxs visitMaxs}.
|
||||||
|
*/
|
||||||
|
static final int PUSHED = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this label is the target of a jump instruction, or the start
|
||||||
|
* of an exception handler.
|
||||||
|
*/
|
||||||
|
static final int TARGET = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if a stack map frame must be stored for this label.
|
||||||
|
*/
|
||||||
|
static final int STORE = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this label corresponds to a reachable basic block.
|
||||||
|
*/
|
||||||
|
static final int REACHABLE = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this basic block ends with a JSR instruction.
|
||||||
|
*/
|
||||||
|
static final int JSR = 128;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this basic block ends with a RET instruction.
|
||||||
|
*/
|
||||||
|
static final int RET = 256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this basic block is the start of a subroutine.
|
||||||
|
*/
|
||||||
|
static final int SUBROUTINE = 512;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this subroutine basic block has been visited by a
|
||||||
|
* visitSubroutine(null, ...) call.
|
||||||
|
*/
|
||||||
|
static final int VISITED = 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this subroutine basic block has been visited by a
|
||||||
|
* visitSubroutine(!null, ...) call.
|
||||||
|
*/
|
||||||
|
static final int VISITED2 = 2048;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field used to associate user information to a label. Warning: this field
|
||||||
|
* is used by the ASM tree package. In order to use it with the ASM tree
|
||||||
|
* package you must override the
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public Object info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags that indicate the status of this label.
|
||||||
|
*
|
||||||
|
* @see #DEBUG
|
||||||
|
* @see #RESOLVED
|
||||||
|
* @see #RESIZED
|
||||||
|
* @see #PUSHED
|
||||||
|
* @see #TARGET
|
||||||
|
* @see #STORE
|
||||||
|
* @see #REACHABLE
|
||||||
|
* @see #JSR
|
||||||
|
* @see #RET
|
||||||
|
*/
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The line number corresponding to this label, if known. If there are
|
||||||
|
* several lines, each line is stored in a separate label, all linked via
|
||||||
|
* their next field (these links are created in ClassReader and removed just
|
||||||
|
* before visitLabel is called, so that this does not impact the rest of the
|
||||||
|
* code).
|
||||||
|
*/
|
||||||
|
int line;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position of this label in the code, if known.
|
||||||
|
*/
|
||||||
|
int position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of forward references to this label, times two.
|
||||||
|
*/
|
||||||
|
private int referenceCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informations about forward references. Each forward reference is
|
||||||
|
* described by two consecutive integers in this array: the first one is the
|
||||||
|
* position of the first byte of the bytecode instruction that contains the
|
||||||
|
* forward reference, while the second is the position of the first byte of
|
||||||
|
* the forward reference itself. In fact the sign of the first integer
|
||||||
|
* indicates if this reference uses 2 or 4 bytes, and its absolute value
|
||||||
|
* gives the position of the bytecode instruction. This array is also used
|
||||||
|
* as a bitset to store the subroutines to which a basic block belongs. This
|
||||||
|
* information is needed in {@linked MethodWriter#visitMaxs}, after all
|
||||||
|
* forward references have been resolved. Hence the same array can be used
|
||||||
|
* for both purposes without problems.
|
||||||
|
*/
|
||||||
|
private int[] srcAndRefPositions;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fields for the control flow and data flow graph analysis algorithms (used
|
||||||
|
* to compute the maximum stack size or the stack map frames). A control
|
||||||
|
* flow graph contains one node per "basic block", and one edge per "jump"
|
||||||
|
* from one basic block to another. Each node (i.e., each basic block) is
|
||||||
|
* represented by the Label object that corresponds to the first instruction
|
||||||
|
* of this basic block. Each node also stores the list of its successors in
|
||||||
|
* the graph, as a linked list of Edge objects.
|
||||||
|
*
|
||||||
|
* The control flow analysis algorithms used to compute the maximum stack
|
||||||
|
* size or the stack map frames are similar and use two steps. The first
|
||||||
|
* step, during the visit of each instruction, builds information about the
|
||||||
|
* state of the local variables and the operand stack at the end of each
|
||||||
|
* basic block, called the "output frame", <i>relatively</i> to the frame
|
||||||
|
* state at the beginning of the basic block, which is called the "input
|
||||||
|
* frame", and which is <i>unknown</i> during this step. The second step, in
|
||||||
|
* {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
|
||||||
|
* information about the input frame of each basic block, from the input
|
||||||
|
* state of the first basic block (known from the method signature), and by
|
||||||
|
* the using the previously computed relative output frames.
|
||||||
|
*
|
||||||
|
* The algorithm used to compute the maximum stack size only computes the
|
||||||
|
* relative output and absolute input stack heights, while the algorithm
|
||||||
|
* used to compute stack map frames computes relative output frames and
|
||||||
|
* absolute input frames.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start of the output stack relatively to the input stack. The exact
|
||||||
|
* semantics of this field depends on the algorithm that is used.
|
||||||
|
*
|
||||||
|
* When only the maximum stack size is computed, this field is the number of
|
||||||
|
* elements in the input stack.
|
||||||
|
*
|
||||||
|
* When the stack map frames are completely computed, this field is the
|
||||||
|
* offset of the first output stack element relatively to the top of the
|
||||||
|
* input stack. This offset is always negative or null. A null offset means
|
||||||
|
* that the output stack must be appended to the input stack. A -n offset
|
||||||
|
* means that the first n output stack elements must replace the top n input
|
||||||
|
* stack elements, and that the other elements must be appended to the input
|
||||||
|
* stack.
|
||||||
|
*/
|
||||||
|
int inputStackTop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum height reached by the output stack, relatively to the top of the
|
||||||
|
* input stack. This maximum is always positive or null.
|
||||||
|
*/
|
||||||
|
int outputStackMax;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the input and output stack map frames of this basic
|
||||||
|
* block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
|
||||||
|
* option is used.
|
||||||
|
*/
|
||||||
|
Frame frame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The successor of this label, in the order they are visited. This linked
|
||||||
|
* list does not include labels used for debug info only. If
|
||||||
|
* {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
|
||||||
|
* does not contain successive labels that denote the same bytecode position
|
||||||
|
* (in this case only the first label appears in this list).
|
||||||
|
*/
|
||||||
|
Label successor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The successors of this node in the control flow graph. These successors
|
||||||
|
* are stored in a linked list of {@link Edge Edge} objects, linked to each
|
||||||
|
* other by their {@link Edge#next} field.
|
||||||
|
*/
|
||||||
|
Edge successors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next basic block in the basic block stack. This stack is used in the
|
||||||
|
* main loop of the fix point algorithm used in the second step of the
|
||||||
|
* control flow analysis algorithms. It is also used in
|
||||||
|
* {@link #visitSubroutine} to avoid using a recursive method, and in
|
||||||
|
* ClassReader to temporarily store multiple source lines for a label.
|
||||||
|
*
|
||||||
|
* @see MethodWriter#visitMaxs
|
||||||
|
*/
|
||||||
|
Label next;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constructor
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new label.
|
||||||
|
*/
|
||||||
|
public Label() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Methods to compute offsets and to manage forward references
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the offset corresponding to this label. This offset is computed
|
||||||
|
* from the start of the method's bytecode. <i>This method is intended for
|
||||||
|
* {@link Attribute} sub classes, and is normally not needed by class
|
||||||
|
* generators or adapters.</i>
|
||||||
|
*
|
||||||
|
* @return the offset corresponding to this label.
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* if this label is not resolved yet.
|
||||||
|
*/
|
||||||
|
public int getOffset() {
|
||||||
|
if ((status & RESOLVED) == 0) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Label offset position has not been resolved yet");
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a reference to this label in the bytecode of a method. If the
|
||||||
|
* position of the label is known, the offset is computed and written
|
||||||
|
* directly. Otherwise, a null offset is written and a new forward reference
|
||||||
|
* is declared for this label.
|
||||||
|
*
|
||||||
|
* @param owner
|
||||||
|
* the code writer that calls this method.
|
||||||
|
* @param out
|
||||||
|
* the bytecode of the method.
|
||||||
|
* @param source
|
||||||
|
* the position of first byte of the bytecode instruction that
|
||||||
|
* contains this label.
|
||||||
|
* @param wideOffset
|
||||||
|
* <tt>true</tt> if the reference must be stored in 4 bytes, or
|
||||||
|
* <tt>false</tt> if it must be stored with 2 bytes.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if this label has not been created by the given code writer.
|
||||||
|
*/
|
||||||
|
void put(final MethodWriter owner, final ByteVector out, final int source,
|
||||||
|
final boolean wideOffset) {
|
||||||
|
if ((status & RESOLVED) == 0) {
|
||||||
|
if (wideOffset) {
|
||||||
|
addReference(-1 - source, out.length);
|
||||||
|
out.putInt(-1);
|
||||||
|
} else {
|
||||||
|
addReference(source, out.length);
|
||||||
|
out.putShort(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wideOffset) {
|
||||||
|
out.putInt(position - source);
|
||||||
|
} else {
|
||||||
|
out.putShort(position - source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a forward reference to this label. This method must be called only
|
||||||
|
* for a true forward reference, i.e. only if this label is not resolved
|
||||||
|
* yet. For backward references, the offset of the reference can be, and
|
||||||
|
* must be, computed and stored directly.
|
||||||
|
*
|
||||||
|
* @param sourcePosition
|
||||||
|
* the position of the referencing instruction. This position
|
||||||
|
* will be used to compute the offset of this forward reference.
|
||||||
|
* @param referencePosition
|
||||||
|
* the position where the offset for this forward reference must
|
||||||
|
* be stored.
|
||||||
|
*/
|
||||||
|
private void addReference(final int sourcePosition,
|
||||||
|
final int referencePosition) {
|
||||||
|
if (srcAndRefPositions == null) {
|
||||||
|
srcAndRefPositions = new int[6];
|
||||||
|
}
|
||||||
|
if (referenceCount >= srcAndRefPositions.length) {
|
||||||
|
int[] a = new int[srcAndRefPositions.length + 6];
|
||||||
|
System.arraycopy(srcAndRefPositions, 0, a, 0,
|
||||||
|
srcAndRefPositions.length);
|
||||||
|
srcAndRefPositions = a;
|
||||||
|
}
|
||||||
|
srcAndRefPositions[referenceCount++] = sourcePosition;
|
||||||
|
srcAndRefPositions[referenceCount++] = referencePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves all forward references to this label. This method must be called
|
||||||
|
* when this label is added to the bytecode of the method, i.e. when its
|
||||||
|
* position becomes known. This method fills in the blanks that where left
|
||||||
|
* in the bytecode by each forward reference previously added to this label.
|
||||||
|
*
|
||||||
|
* @param owner
|
||||||
|
* the code writer that calls this method.
|
||||||
|
* @param position
|
||||||
|
* the position of this label in the bytecode.
|
||||||
|
* @param data
|
||||||
|
* the bytecode of the method.
|
||||||
|
* @return <tt>true</tt> if a blank that was left for this label was too
|
||||||
|
* small to store the offset. In such a case the corresponding jump
|
||||||
|
* instruction is replaced with a pseudo instruction (using unused
|
||||||
|
* opcodes) using an unsigned two bytes offset. These pseudo
|
||||||
|
* instructions will be replaced with standard bytecode instructions
|
||||||
|
* with wider offsets (4 bytes instead of 2), in ClassReader.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if this label has already been resolved, or if it has not
|
||||||
|
* been created by the given code writer.
|
||||||
|
*/
|
||||||
|
boolean resolve(final MethodWriter owner, final int position,
|
||||||
|
final byte[] data) {
|
||||||
|
boolean needUpdate = false;
|
||||||
|
this.status |= RESOLVED;
|
||||||
|
this.position = position;
|
||||||
|
int i = 0;
|
||||||
|
while (i < referenceCount) {
|
||||||
|
int source = srcAndRefPositions[i++];
|
||||||
|
int reference = srcAndRefPositions[i++];
|
||||||
|
int offset;
|
||||||
|
if (source >= 0) {
|
||||||
|
offset = position - source;
|
||||||
|
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
|
||||||
|
/*
|
||||||
|
* changes the opcode of the jump instruction, in order to
|
||||||
|
* be able to find it later (see resizeInstructions in
|
||||||
|
* MethodWriter). These temporary opcodes are similar to
|
||||||
|
* jump instruction opcodes, except that the 2 bytes offset
|
||||||
|
* is unsigned (and can therefore represent values from 0 to
|
||||||
|
* 65535, which is sufficient since the size of a method is
|
||||||
|
* limited to 65535 bytes).
|
||||||
|
*/
|
||||||
|
int opcode = data[reference - 1] & 0xFF;
|
||||||
|
if (opcode <= Opcodes.JSR) {
|
||||||
|
// changes IFEQ ... JSR to opcodes 202 to 217
|
||||||
|
data[reference - 1] = (byte) (opcode + 49);
|
||||||
|
} else {
|
||||||
|
// changes IFNULL and IFNONNULL to opcodes 218 and 219
|
||||||
|
data[reference - 1] = (byte) (opcode + 20);
|
||||||
|
}
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
data[reference++] = (byte) (offset >>> 8);
|
||||||
|
data[reference] = (byte) offset;
|
||||||
|
} else {
|
||||||
|
offset = position + source + 1;
|
||||||
|
data[reference++] = (byte) (offset >>> 24);
|
||||||
|
data[reference++] = (byte) (offset >>> 16);
|
||||||
|
data[reference++] = (byte) (offset >>> 8);
|
||||||
|
data[reference] = (byte) offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return needUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first label of the series to which this label belongs. For an
|
||||||
|
* isolated label or for the first label in a series of successive labels,
|
||||||
|
* this method returns the label itself. For other labels it returns the
|
||||||
|
* first label of the series.
|
||||||
|
*
|
||||||
|
* @return the first label of the series to which this label belongs.
|
||||||
|
*/
|
||||||
|
Label getFirst() {
|
||||||
|
return frame == null ? this : frame.owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Methods related to subroutines
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true is this basic block belongs to the given subroutine.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* a subroutine id.
|
||||||
|
* @return true is this basic block belongs to the given subroutine.
|
||||||
|
*/
|
||||||
|
boolean inSubroutine(final long id) {
|
||||||
|
if ((status & Label.VISITED) != 0) {
|
||||||
|
return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this basic block and the given one belong to a common
|
||||||
|
* subroutine.
|
||||||
|
*
|
||||||
|
* @param block
|
||||||
|
* another basic block.
|
||||||
|
* @return true if this basic block and the given one belong to a common
|
||||||
|
* subroutine.
|
||||||
|
*/
|
||||||
|
boolean inSameSubroutine(final Label block) {
|
||||||
|
if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < srcAndRefPositions.length; ++i) {
|
||||||
|
if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks this basic block as belonging to the given subroutine.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* a subroutine id.
|
||||||
|
* @param nbSubroutines
|
||||||
|
* the total number of subroutines in the method.
|
||||||
|
*/
|
||||||
|
void addToSubroutine(final long id, final int nbSubroutines) {
|
||||||
|
if ((status & VISITED) == 0) {
|
||||||
|
status |= VISITED;
|
||||||
|
srcAndRefPositions = new int[nbSubroutines / 32 + 1];
|
||||||
|
}
|
||||||
|
srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the basic blocks that belong to a given subroutine, and marks these
|
||||||
|
* blocks as belonging to this subroutine. This method follows the control
|
||||||
|
* flow graph to find all the blocks that are reachable from the current
|
||||||
|
* block WITHOUT following any JSR target.
|
||||||
|
*
|
||||||
|
* @param JSR
|
||||||
|
* a JSR block that jumps to this subroutine. If this JSR is not
|
||||||
|
* null it is added to the successor of the RET blocks found in
|
||||||
|
* the subroutine.
|
||||||
|
* @param id
|
||||||
|
* the id of this subroutine.
|
||||||
|
* @param nbSubroutines
|
||||||
|
* the total number of subroutines in the method.
|
||||||
|
*/
|
||||||
|
void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
|
||||||
|
// user managed stack of labels, to avoid using a recursive method
|
||||||
|
// (recursivity can lead to stack overflow with very large methods)
|
||||||
|
Label stack = this;
|
||||||
|
while (stack != null) {
|
||||||
|
// removes a label l from the stack
|
||||||
|
Label l = stack;
|
||||||
|
stack = l.next;
|
||||||
|
l.next = null;
|
||||||
|
|
||||||
|
if (JSR != null) {
|
||||||
|
if ((l.status & VISITED2) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
l.status |= VISITED2;
|
||||||
|
// adds JSR to the successors of l, if it is a RET block
|
||||||
|
if ((l.status & RET) != 0) {
|
||||||
|
if (!l.inSameSubroutine(JSR)) {
|
||||||
|
Edge e = new Edge();
|
||||||
|
e.info = l.inputStackTop;
|
||||||
|
e.successor = JSR.successors.successor;
|
||||||
|
e.next = l.successors;
|
||||||
|
l.successors = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if the l block already belongs to subroutine 'id', continue
|
||||||
|
if (l.inSubroutine(id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// marks the l block as belonging to subroutine 'id'
|
||||||
|
l.addToSubroutine(id, nbSubroutines);
|
||||||
|
}
|
||||||
|
// pushes each successor of l on the stack, except JSR targets
|
||||||
|
Edge e = l.successors;
|
||||||
|
while (e != null) {
|
||||||
|
// if the l block is a JSR block, then 'l.successors.next' leads
|
||||||
|
// to the JSR target (see {@link #visitJumpInsn}) and must
|
||||||
|
// therefore not be followed
|
||||||
|
if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
|
||||||
|
// pushes e.successor on the stack if it not already added
|
||||||
|
if (e.successor.next == null) {
|
||||||
|
e.successor.next = stack;
|
||||||
|
stack = e.successor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e = e.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Overriden Object methods
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this label.
|
||||||
|
*
|
||||||
|
* @return a string representation of this label.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "L" + System.identityHashCode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,10 +3,12 @@
|
|||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package org.redkale.util;
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import jdk.internal.org.objectweb.asm.*;
|
import static org.redkale.asm.Opcodes.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MethodVisitor 的调试类
|
* MethodVisitor 的调试类
|
||||||
@@ -15,13 +17,13 @@ import jdk.internal.org.objectweb.asm.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class AsmMethodVisitor {
|
public class MethodDebugVisitor {
|
||||||
|
|
||||||
private final MethodVisitor visitor;
|
private final MethodVisitor visitor;
|
||||||
|
|
||||||
private boolean debug = false;
|
private boolean debug = false;
|
||||||
|
|
||||||
public AsmMethodVisitor setDebug(boolean d) {
|
public MethodDebugVisitor setDebug(boolean d) {
|
||||||
debug = d;
|
debug = d;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -33,7 +35,7 @@ public class AsmMethodVisitor {
|
|||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<Label, Integer> labels = new LinkedHashMap();
|
private final Map<Label, Integer> labels = new LinkedHashMap<>();
|
||||||
|
|
||||||
private static final String[] opcodes = new String[200]; //0 -18
|
private static final String[] opcodes = new String[200]; //0 -18
|
||||||
|
|
||||||
@@ -55,11 +57,20 @@ public class AsmMethodVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsmMethodVisitor(MethodVisitor visitor) {
|
/**
|
||||||
|
*
|
||||||
|
* @param visitor MethodVisitor
|
||||||
|
*/
|
||||||
|
public MethodDebugVisitor(MethodVisitor visitor) {
|
||||||
//super(Opcodes.ASM5, visitor);
|
//super(Opcodes.ASM5, visitor);
|
||||||
this.visitor = visitor;
|
this.visitor = visitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
|
||||||
|
visitor.visitTryCatchBlock(start, end, handler, type);
|
||||||
|
if (debug) System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");");
|
||||||
|
}
|
||||||
|
|
||||||
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
|
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
|
||||||
AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln);
|
AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln);
|
||||||
if (debug) System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");");
|
if (debug) System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");");
|
||||||
@@ -173,7 +184,7 @@ public class AsmMethodVisitor {
|
|||||||
if (debug) {
|
if (debug) {
|
||||||
if (o instanceof CharSequence) {
|
if (o instanceof CharSequence) {
|
||||||
System.out.println("mv.visitLdcInsn(\"" + o + "\");");
|
System.out.println("mv.visitLdcInsn(\"" + o + "\");");
|
||||||
} else if (o instanceof jdk.internal.org.objectweb.asm.Type) {
|
} else if (o instanceof org.redkale.asm.Type) {
|
||||||
System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
|
System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
|
||||||
} else {
|
} else {
|
||||||
System.out.println("mv.visitLdcInsn(" + o + ");");
|
System.out.println("mv.visitLdcInsn(" + o + ");");
|
||||||
@@ -190,4 +201,74 @@ public class AsmMethodVisitor {
|
|||||||
visitor.visitEnd();
|
visitor.visitEnd();
|
||||||
if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n");
|
if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void pushInt(MethodDebugVisitor mv, int num) {
|
||||||
|
if (num < 6) {
|
||||||
|
mv.visitInsn(ICONST_0 + num);
|
||||||
|
} else if (num <= Byte.MAX_VALUE) {
|
||||||
|
mv.visitIntInsn(BIPUSH, num);
|
||||||
|
} else if (num <= Short.MAX_VALUE) {
|
||||||
|
mv.visitIntInsn(SIPUSH, num);
|
||||||
|
} else {
|
||||||
|
mv.visitLdcInsn(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void pushInt(MethodVisitor mv, int num) {
|
||||||
|
if (num < 6) {
|
||||||
|
mv.visitInsn(ICONST_0 + num);
|
||||||
|
} else if (num <= Byte.MAX_VALUE) {
|
||||||
|
mv.visitIntInsn(BIPUSH, num);
|
||||||
|
} else if (num <= Short.MAX_VALUE) {
|
||||||
|
mv.visitIntInsn(SIPUSH, num);
|
||||||
|
} else {
|
||||||
|
mv.visitLdcInsn(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
|
||||||
|
try {
|
||||||
|
for (Method anm : ann.annotationType().getMethods()) {
|
||||||
|
final String mname = anm.getName();
|
||||||
|
if ("equals".equals(mname) || "hashCode".equals(mname) || "toString".equals(mname) || "annotationType".equals(mname)) continue;
|
||||||
|
final Object r = anm.invoke(ann);
|
||||||
|
if (r instanceof String[]) {
|
||||||
|
AnnotationVisitor av1 = av.visitArray(mname);
|
||||||
|
for (String item : (String[]) r) {
|
||||||
|
av1.visit(null, item);
|
||||||
|
}
|
||||||
|
av1.visitEnd();
|
||||||
|
} else if (r instanceof Class[]) {
|
||||||
|
AnnotationVisitor av1 = av.visitArray(mname);
|
||||||
|
for (Class item : (Class[]) r) {
|
||||||
|
av1.visit(null, Type.getType(item));
|
||||||
|
}
|
||||||
|
av1.visitEnd();
|
||||||
|
} else if (r instanceof Enum[]) {
|
||||||
|
AnnotationVisitor av1 = av.visitArray(mname);
|
||||||
|
for (Enum item : (Enum[]) r) {
|
||||||
|
av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
|
||||||
|
}
|
||||||
|
av1.visitEnd();
|
||||||
|
} else if (r instanceof Annotation[]) {
|
||||||
|
AnnotationVisitor av1 = av.visitArray(mname);
|
||||||
|
for (Annotation item : (Annotation[]) r) {
|
||||||
|
visitAnnotation(av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), item);
|
||||||
|
}
|
||||||
|
av1.visitEnd();
|
||||||
|
} else if (r instanceof Class) {
|
||||||
|
av.visit(mname, Type.getType((Class) r));
|
||||||
|
} else if (r instanceof Enum) {
|
||||||
|
av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
|
||||||
|
} else if (r instanceof Annotation) {
|
||||||
|
visitAnnotation(av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), (Annotation) r);
|
||||||
|
} else {
|
||||||
|
av.visit(mname, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av.visitEnd();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
855
src/main/java/org/redkale/asm/MethodVisitor.java
Normal file
855
src/main/java/org/redkale/asm/MethodVisitor.java
Normal file
@@ -0,0 +1,855 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A visitor to visit a Java method. The methods of this class must be called in
|
||||||
|
* the following order: ( <tt>visitParameter</tt> )* [
|
||||||
|
* <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
|
||||||
|
* <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> |
|
||||||
|
* <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
|
||||||
|
* <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> |
|
||||||
|
* <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> |
|
||||||
|
* <tt>visitTryCatchAnnotation</tt> | <tt>visitLocalVariable</tt> |
|
||||||
|
* <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )*
|
||||||
|
* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the
|
||||||
|
* <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must be called in
|
||||||
|
* the sequential order of the bytecode instructions of the visited code,
|
||||||
|
* <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
|
||||||
|
* instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
|
||||||
|
* labels passed as arguments have been visited,
|
||||||
|
* <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
|
||||||
|
* corresponding try catch block has been visited, and the
|
||||||
|
* <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
|
||||||
|
* <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
|
||||||
|
* passed as arguments have been visited.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public abstract class MethodVisitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ASM API version implemented by this visitor. The value of this field
|
||||||
|
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
protected final int api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method visitor to which this visitor must delegate method calls. May
|
||||||
|
* be null.
|
||||||
|
*/
|
||||||
|
protected MethodVisitor mv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link MethodVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
public MethodVisitor(final int api) {
|
||||||
|
this(api, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link MethodVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be one
|
||||||
|
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||||
|
* @param mv
|
||||||
|
* the method visitor to which this visitor must delegate method
|
||||||
|
* calls. May be null.
|
||||||
|
*/
|
||||||
|
public MethodVisitor(final int api, final MethodVisitor mv) {
|
||||||
|
this.api = api;
|
||||||
|
this.mv = mv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Parameters, annotations and non standard attributes
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a parameter of this method.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* parameter name or null if none is provided.
|
||||||
|
* @param access
|
||||||
|
* the parameter's access flags, only <tt>ACC_FINAL</tt>,
|
||||||
|
* <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
|
||||||
|
* allowed (see {@link Opcodes}).
|
||||||
|
*/
|
||||||
|
public void visitParameter(String name, int access) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitParameter(name, access);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the default value of this annotation interface method.
|
||||||
|
*
|
||||||
|
* @return a visitor to the visit the actual default value of this
|
||||||
|
* annotation interface method, or <tt>null</tt> if this visitor is
|
||||||
|
* not interested in visiting this default value. The 'name'
|
||||||
|
* parameters passed to the methods of this annotation visitor are
|
||||||
|
* ignored. Moreover, exacly one visit method must be called on this
|
||||||
|
* annotation visitor, followed by visitEnd.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitAnnotationDefault() {
|
||||||
|
if (mv != null) {
|
||||||
|
return mv.visitAnnotationDefault();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation of this method.
|
||||||
|
*
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||||
|
if (mv != null) {
|
||||||
|
return mv.visitAnnotation(desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation on a type in the method signature.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* a reference to the annotated type. The sort of this type
|
||||||
|
* reference must be {@link TypeReference#METHOD_TYPE_PARAMETER
|
||||||
|
* METHOD_TYPE_PARAMETER},
|
||||||
|
* {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND
|
||||||
|
* METHOD_TYPE_PARAMETER_BOUND},
|
||||||
|
* {@link TypeReference#METHOD_RETURN METHOD_RETURN},
|
||||||
|
* {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
|
||||||
|
* {@link TypeReference#METHOD_FORMAL_PARAMETER
|
||||||
|
* METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS
|
||||||
|
* THROWS}. See {@link TypeReference}.
|
||||||
|
* @param typePath
|
||||||
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
|
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||||
|
TypePath typePath, String desc, boolean visible) {
|
||||||
|
if (mv != null) {
|
||||||
|
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation of a parameter this method.
|
||||||
|
*
|
||||||
|
* @param parameter
|
||||||
|
* the parameter index.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitParameterAnnotation(int parameter,
|
||||||
|
String desc, boolean visible) {
|
||||||
|
if (mv != null) {
|
||||||
|
return mv.visitParameterAnnotation(parameter, desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a non standard attribute of this method.
|
||||||
|
*
|
||||||
|
* @param attr
|
||||||
|
* an attribute.
|
||||||
|
*/
|
||||||
|
public void visitAttribute(Attribute attr) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitAttribute(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the visit of the method's code, if any (i.e. non abstract method).
|
||||||
|
*/
|
||||||
|
public void visitCode() {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the current state of the local variables and operand stack
|
||||||
|
* elements. This method must(*) be called <i>just before</i> any
|
||||||
|
* instruction <b>i</b> that follows an unconditional branch instruction
|
||||||
|
* such as GOTO or THROW, that is the target of a jump instruction, or that
|
||||||
|
* starts an exception handler block. The visited types must describe the
|
||||||
|
* values of the local variables and of the operand stack elements <i>just
|
||||||
|
* before</i> <b>i</b> is executed.<br>
|
||||||
|
* <br>
|
||||||
|
* (*) this is mandatory only for classes whose version is greater than or
|
||||||
|
* equal to {@link Opcodes#V1_6 V1_6}. <br>
|
||||||
|
* <br>
|
||||||
|
* The frames of a method must be given either in expanded form, or in
|
||||||
|
* compressed form (all frames must use the same format, i.e. you must not
|
||||||
|
* mix expanded and compressed frames within a single method):
|
||||||
|
* <ul>
|
||||||
|
* <li>In expanded form, all frames must have the F_NEW type.</li>
|
||||||
|
* <li>In compressed form, frames are basically "deltas" from the state of
|
||||||
|
* the previous frame:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link Opcodes#F_SAME} representing frame with exactly the same
|
||||||
|
* locals as the previous frame and with the empty stack.</li>
|
||||||
|
* <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
|
||||||
|
* locals as the previous frame and with single value on the stack (
|
||||||
|
* <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
|
||||||
|
* type of the stack item).</li>
|
||||||
|
* <li>{@link Opcodes#F_APPEND} representing frame with current locals are
|
||||||
|
* the same as the locals in the previous frame, except that additional
|
||||||
|
* locals are defined (<code>nLocal</code> is 1, 2 or 3 and
|
||||||
|
* <code>local</code> elements contains values representing added types).</li>
|
||||||
|
* <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
|
||||||
|
* same as the locals in the previous frame, except that the last 1-3 locals
|
||||||
|
* are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
|
||||||
|
* <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* <br>
|
||||||
|
* In both cases the first frame, corresponding to the method's parameters
|
||||||
|
* and access flags, is implicit and must not be visited. Also, it is
|
||||||
|
* illegal to visit two or more frames for the same code location (i.e., at
|
||||||
|
* least one instruction must be visited between two calls to visitFrame).
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* the type of this stack map frame. Must be
|
||||||
|
* {@link Opcodes#F_NEW} for expanded frames, or
|
||||||
|
* {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
|
||||||
|
* {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
|
||||||
|
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
|
||||||
|
* compressed frames.
|
||||||
|
* @param nLocal
|
||||||
|
* the number of local variables in the visited frame.
|
||||||
|
* @param local
|
||||||
|
* the local variable types in this frame. This array must not be
|
||||||
|
* modified. Primitive types are represented by
|
||||||
|
* {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
|
||||||
|
* {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
|
||||||
|
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
|
||||||
|
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are
|
||||||
|
* represented by a single element). Reference types are
|
||||||
|
* represented by String objects (representing internal names),
|
||||||
|
* and uninitialized types by Label objects (this label
|
||||||
|
* designates the NEW instruction that created this uninitialized
|
||||||
|
* value).
|
||||||
|
* @param nStack
|
||||||
|
* the number of operand stack elements in the visited frame.
|
||||||
|
* @param stack
|
||||||
|
* the operand stack types in this frame. This array must not be
|
||||||
|
* modified. Its content has the same format as the "local"
|
||||||
|
* array.
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* if a frame is visited just after another one, without any
|
||||||
|
* instruction between the two (unless this frame is a
|
||||||
|
* Opcodes#F_SAME frame, in which case it is silently ignored).
|
||||||
|
*/
|
||||||
|
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
|
||||||
|
Object[] stack) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitFrame(type, nLocal, local, nStack, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Normal instructions
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a zero operand instruction.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* the opcode of the instruction to be visited. This opcode is
|
||||||
|
* either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
|
||||||
|
* ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
|
||||||
|
* FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
|
||||||
|
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
|
||||||
|
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
|
||||||
|
* SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
|
||||||
|
* DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
|
||||||
|
* IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
|
||||||
|
* FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
|
||||||
|
* IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
|
||||||
|
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
|
||||||
|
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
|
||||||
|
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
|
||||||
|
* or MONITOREXIT.
|
||||||
|
*/
|
||||||
|
public void visitInsn(int opcode) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitInsn(opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an instruction with a single int operand.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* the opcode of the instruction to be visited. This opcode is
|
||||||
|
* either BIPUSH, SIPUSH or NEWARRAY.
|
||||||
|
* @param operand
|
||||||
|
* the operand of the instruction to be visited.<br>
|
||||||
|
* When opcode is BIPUSH, operand value should be between
|
||||||
|
* Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
|
||||||
|
* When opcode is SIPUSH, operand value should be between
|
||||||
|
* Short.MIN_VALUE and Short.MAX_VALUE.<br>
|
||||||
|
* When opcode is NEWARRAY, operand value should be one of
|
||||||
|
* {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
|
||||||
|
* {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
|
||||||
|
* {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
|
||||||
|
* {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
|
||||||
|
*/
|
||||||
|
public void visitIntInsn(int opcode, int operand) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitIntInsn(opcode, operand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a local variable instruction. A local variable instruction is an
|
||||||
|
* instruction that loads or stores the value of a local variable.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* the opcode of the local variable instruction to be visited.
|
||||||
|
* This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
|
||||||
|
* ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
|
||||||
|
* @param var
|
||||||
|
* the operand of the instruction to be visited. This operand is
|
||||||
|
* the index of a local variable.
|
||||||
|
*/
|
||||||
|
public void visitVarInsn(int opcode, int var) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitVarInsn(opcode, var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a type instruction. A type instruction is an instruction that
|
||||||
|
* takes the internal name of a class as parameter.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* the opcode of the type instruction to be visited. This opcode
|
||||||
|
* is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
|
||||||
|
* @param type
|
||||||
|
* the operand of the instruction to be visited. This operand
|
||||||
|
* must be the internal name of an object or array class (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}).
|
||||||
|
*/
|
||||||
|
public void visitTypeInsn(int opcode, String type) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitTypeInsn(opcode, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a field instruction. A field instruction is an instruction that
|
||||||
|
* loads or stores the value of a field of an object.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* the opcode of the type instruction to be visited. This opcode
|
||||||
|
* is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
|
||||||
|
* @param owner
|
||||||
|
* the internal name of the field's owner class (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}).
|
||||||
|
* @param name
|
||||||
|
* the field's name.
|
||||||
|
* @param desc
|
||||||
|
* the field's descriptor (see {@link Type Type}).
|
||||||
|
*/
|
||||||
|
public void visitFieldInsn(int opcode, String owner, String name,
|
||||||
|
String desc) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitFieldInsn(opcode, owner, name, desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a method instruction. A method instruction is an instruction that
|
||||||
|
* invokes a method.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* the opcode of the type instruction to be visited. This opcode
|
||||||
|
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
|
||||||
|
* INVOKEINTERFACE.
|
||||||
|
* @param owner
|
||||||
|
* the internal name of the method's owner class (see
|
||||||
|
* {@link Type#getInternalName() getInternalName}).
|
||||||
|
* @param name
|
||||||
|
* the method's name.
|
||||||
|
* @param desc
|
||||||
|
* the method's descriptor (see {@link Type Type}).
|
||||||
|
* @param itf
|
||||||
|
* if the method's owner class is an interface.
|
||||||
|
*/
|
||||||
|
public void visitMethodInsn(int opcode, String owner, String name,
|
||||||
|
String desc, boolean itf) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an invokedynamic instruction.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the method's name.
|
||||||
|
* @param desc
|
||||||
|
* the method's descriptor (see {@link Type Type}).
|
||||||
|
* @param bsm
|
||||||
|
* the bootstrap method.
|
||||||
|
* @param bsmArgs
|
||||||
|
* the bootstrap method constant arguments. Each argument must be
|
||||||
|
* an {@link Integer}, {@link Float}, {@link Long},
|
||||||
|
* {@link Double}, {@link String}, {@link Type} or {@link Handle}
|
||||||
|
* value. This method is allowed to modify the content of the
|
||||||
|
* array so a caller should expect that this array may change.
|
||||||
|
*/
|
||||||
|
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||||
|
Object... bsmArgs) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a jump instruction. A jump instruction is an instruction that may
|
||||||
|
* jump to another instruction.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* the opcode of the type instruction to be visited. This opcode
|
||||||
|
* is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
|
||||||
|
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
|
||||||
|
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
|
||||||
|
* @param label
|
||||||
|
* the operand of the instruction to be visited. This operand is
|
||||||
|
* a label that designates the instruction to which the jump
|
||||||
|
* instruction may jump.
|
||||||
|
*/
|
||||||
|
public void visitJumpInsn(int opcode, Label label) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitJumpInsn(opcode, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a label. A label designates the instruction that will be visited
|
||||||
|
* just after it.
|
||||||
|
*
|
||||||
|
* @param label
|
||||||
|
* a {@link Label Label} object.
|
||||||
|
*/
|
||||||
|
public void visitLabel(Label label) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitLabel(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Special instructions
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a LDC instruction. Note that new constant types may be added in
|
||||||
|
* future versions of the Java Virtual Machine. To easily detect new
|
||||||
|
* constant types, implementations of this method should check for
|
||||||
|
* unexpected constant types, like this:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* if (cst instanceof Integer) {
|
||||||
|
* // ...
|
||||||
|
* } else if (cst instanceof Float) {
|
||||||
|
* // ...
|
||||||
|
* } else if (cst instanceof Long) {
|
||||||
|
* // ...
|
||||||
|
* } else if (cst instanceof Double) {
|
||||||
|
* // ...
|
||||||
|
* } else if (cst instanceof String) {
|
||||||
|
* // ...
|
||||||
|
* } else if (cst instanceof Type) {
|
||||||
|
* int sort = ((Type) cst).getSort();
|
||||||
|
* if (sort == Type.OBJECT) {
|
||||||
|
* // ...
|
||||||
|
* } else if (sort == Type.ARRAY) {
|
||||||
|
* // ...
|
||||||
|
* } else if (sort == Type.METHOD) {
|
||||||
|
* // ...
|
||||||
|
* } else {
|
||||||
|
* // throw an exception
|
||||||
|
* }
|
||||||
|
* } else if (cst instanceof Handle) {
|
||||||
|
* // ...
|
||||||
|
* } else {
|
||||||
|
* // throw an exception
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param cst
|
||||||
|
* the constant to be loaded on the stack. This parameter must be
|
||||||
|
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
|
||||||
|
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
|
||||||
|
* ARRAY sort for <tt>.class</tt> constants, for classes whose
|
||||||
|
* version is 49.0, a {@link Type} of METHOD sort or a
|
||||||
|
* {@link Handle} for MethodType and MethodHandle constants, for
|
||||||
|
* classes whose version is 51.0.
|
||||||
|
*/
|
||||||
|
public void visitLdcInsn(Object cst) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitLdcInsn(cst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an IINC instruction.
|
||||||
|
*
|
||||||
|
* @param var
|
||||||
|
* index of the local variable to be incremented.
|
||||||
|
* @param increment
|
||||||
|
* amount to increment the local variable by.
|
||||||
|
*/
|
||||||
|
public void visitIincInsn(int var, int increment) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitIincInsn(var, increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a TABLESWITCH instruction.
|
||||||
|
*
|
||||||
|
* @param min
|
||||||
|
* the minimum key value.
|
||||||
|
* @param max
|
||||||
|
* the maximum key value.
|
||||||
|
* @param dflt
|
||||||
|
* beginning of the default handler block.
|
||||||
|
* @param labels
|
||||||
|
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
|
||||||
|
* beginning of the handler block for the <tt>min + i</tt> key.
|
||||||
|
*/
|
||||||
|
public void visitTableSwitchInsn(int min, int max, Label dflt,
|
||||||
|
Label... labels) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitTableSwitchInsn(min, max, dflt, labels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a LOOKUPSWITCH instruction.
|
||||||
|
*
|
||||||
|
* @param dflt
|
||||||
|
* beginning of the default handler block.
|
||||||
|
* @param keys
|
||||||
|
* the values of the keys.
|
||||||
|
* @param labels
|
||||||
|
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
|
||||||
|
* beginning of the handler block for the <tt>keys[i]</tt> key.
|
||||||
|
*/
|
||||||
|
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitLookupSwitchInsn(dflt, keys, labels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a MULTIANEWARRAY instruction.
|
||||||
|
*
|
||||||
|
* @param desc
|
||||||
|
* an array type descriptor (see {@link Type Type}).
|
||||||
|
* @param dims
|
||||||
|
* number of dimensions of the array to allocate.
|
||||||
|
*/
|
||||||
|
public void visitMultiANewArrayInsn(String desc, int dims) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitMultiANewArrayInsn(desc, dims);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation on an instruction. This method must be called just
|
||||||
|
* <i>after</i> the annotated instruction. It can be called several times
|
||||||
|
* for the same instruction.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* a reference to the annotated type. The sort of this type
|
||||||
|
* reference must be {@link TypeReference#INSTANCEOF INSTANCEOF},
|
||||||
|
* {@link TypeReference#NEW NEW},
|
||||||
|
* {@link TypeReference#CONSTRUCTOR_REFERENCE
|
||||||
|
* CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
|
||||||
|
* METHOD_REFERENCE}, {@link TypeReference#CAST CAST},
|
||||||
|
* {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
|
||||||
|
* METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||||
|
* {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
|
||||||
|
* METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
|
||||||
|
* @param typePath
|
||||||
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
|
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitInsnAnnotation(int typeRef,
|
||||||
|
TypePath typePath, String desc, boolean visible) {
|
||||||
|
if (mv != null) {
|
||||||
|
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Exceptions table entries, debug information, max stack and max locals
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a try catch block.
|
||||||
|
*
|
||||||
|
* @param start
|
||||||
|
* beginning of the exception handler's scope (inclusive).
|
||||||
|
* @param end
|
||||||
|
* end of the exception handler's scope (exclusive).
|
||||||
|
* @param handler
|
||||||
|
* beginning of the exception handler's code.
|
||||||
|
* @param type
|
||||||
|
* internal name of the type of exceptions handled by the
|
||||||
|
* handler, or <tt>null</tt> to catch any exceptions (for
|
||||||
|
* "finally" blocks).
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if one of the labels has already been visited by this visitor
|
||||||
|
* (by the {@link #visitLabel visitLabel} method).
|
||||||
|
*/
|
||||||
|
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
||||||
|
String type) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitTryCatchBlock(start, end, handler, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation on an exception handler type. This method must be
|
||||||
|
* called <i>after</i> the {@link #visitTryCatchBlock} for the annotated
|
||||||
|
* exception handler. It can be called several times for the same exception
|
||||||
|
* handler.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* a reference to the annotated type. The sort of this type
|
||||||
|
* reference must be {@link TypeReference#EXCEPTION_PARAMETER
|
||||||
|
* EXCEPTION_PARAMETER}. See {@link TypeReference}.
|
||||||
|
* @param typePath
|
||||||
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
|
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
|
||||||
|
TypePath typePath, String desc, boolean visible) {
|
||||||
|
if (mv != null) {
|
||||||
|
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a local variable declaration.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the name of a local variable.
|
||||||
|
* @param desc
|
||||||
|
* the type descriptor of this local variable.
|
||||||
|
* @param signature
|
||||||
|
* the type signature of this local variable. May be
|
||||||
|
* <tt>null</tt> if the local variable type does not use generic
|
||||||
|
* types.
|
||||||
|
* @param start
|
||||||
|
* the first instruction corresponding to the scope of this local
|
||||||
|
* variable (inclusive).
|
||||||
|
* @param end
|
||||||
|
* the last instruction corresponding to the scope of this local
|
||||||
|
* variable (exclusive).
|
||||||
|
* @param index
|
||||||
|
* the local variable's index.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if one of the labels has not already been visited by this
|
||||||
|
* visitor (by the {@link #visitLabel visitLabel} method).
|
||||||
|
*/
|
||||||
|
public void visitLocalVariable(String name, String desc, String signature,
|
||||||
|
Label start, Label end, int index) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitLocalVariable(name, desc, signature, start, end, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an annotation on a local variable type.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* a reference to the annotated type. The sort of this type
|
||||||
|
* reference must be {@link TypeReference#LOCAL_VARIABLE
|
||||||
|
* LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
|
||||||
|
* RESOURCE_VARIABLE}. See {@link TypeReference}.
|
||||||
|
* @param typePath
|
||||||
|
* the path to the annotated type argument, wildcard bound, array
|
||||||
|
* element type, or static inner type within 'typeRef'. May be
|
||||||
|
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||||
|
* @param start
|
||||||
|
* the fist instructions corresponding to the continuous ranges
|
||||||
|
* that make the scope of this local variable (inclusive).
|
||||||
|
* @param end
|
||||||
|
* the last instructions corresponding to the continuous ranges
|
||||||
|
* that make the scope of this local variable (exclusive). This
|
||||||
|
* array must have the same size as the 'start' array.
|
||||||
|
* @param index
|
||||||
|
* the local variable's index in each range. This array must have
|
||||||
|
* the same size as the 'start' array.
|
||||||
|
* @param desc
|
||||||
|
* the class descriptor of the annotation class.
|
||||||
|
* @param visible
|
||||||
|
* <tt>true</tt> if the annotation is visible at runtime.
|
||||||
|
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||||
|
* this visitor is not interested in visiting this annotation.
|
||||||
|
*/
|
||||||
|
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
||||||
|
TypePath typePath, Label[] start, Label[] end, int[] index,
|
||||||
|
String desc, boolean visible) {
|
||||||
|
if (mv != null) {
|
||||||
|
return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
|
||||||
|
end, index, desc, visible);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a line number declaration.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* a line number. This number refers to the source file from
|
||||||
|
* which the class was compiled.
|
||||||
|
* @param start
|
||||||
|
* the first instruction corresponding to this line number.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if <tt>start</tt> has not already been visited by this
|
||||||
|
* visitor (by the {@link #visitLabel visitLabel} method).
|
||||||
|
*/
|
||||||
|
public void visitLineNumber(int line, Label start) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitLineNumber(line, start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the maximum stack size and the maximum number of local variables
|
||||||
|
* of the method.
|
||||||
|
*
|
||||||
|
* @param maxStack
|
||||||
|
* maximum stack size of the method.
|
||||||
|
* @param maxLocals
|
||||||
|
* maximum number of local variables for the method.
|
||||||
|
*/
|
||||||
|
public void visitMaxs(int maxStack, int maxLocals) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitMaxs(maxStack, maxLocals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the end of the method. This method, which is the last one to be
|
||||||
|
* called, is used to inform the visitor that all the annotations and
|
||||||
|
* attributes of the method have been visited.
|
||||||
|
*/
|
||||||
|
public void visitEnd() {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2402
src/main/java/org/redkale/asm/MethodWriter.java
Normal file
2402
src/main/java/org/redkale/asm/MethodWriter.java
Normal file
File diff suppressed because it is too large
Load Diff
219
src/main/java/org/redkale/asm/ModuleVisitor.java
Normal file
219
src/main/java/org/redkale/asm/ModuleVisitor.java
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A visitor to visit a Java module. The methods of this class must be called in
|
||||||
|
* the following order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> |
|
||||||
|
* <tt>visitRequire</tt> | <tt>visitExport</tt> | <tt>visitOpen</tt> |
|
||||||
|
* <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
|
||||||
|
*
|
||||||
|
* The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
|
||||||
|
* {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
|
||||||
|
* take as parameter a package name or a module name. Unlike the other names which are internal names
|
||||||
|
* (names separated by slash), module and package names are qualified names (names separated by dot).
|
||||||
|
*
|
||||||
|
* @author Remi Forax
|
||||||
|
*/
|
||||||
|
public abstract class ModuleVisitor {
|
||||||
|
/**
|
||||||
|
* The ASM API version implemented by this visitor. The value of this field
|
||||||
|
* must be {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
protected final int api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module visitor to which this visitor must delegate method calls. May
|
||||||
|
* be null.
|
||||||
|
*/
|
||||||
|
protected ModuleVisitor mv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link ModuleVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
|
||||||
|
*/
|
||||||
|
public ModuleVisitor(final int api) {
|
||||||
|
this(api, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link ModuleVisitor}.
|
||||||
|
*
|
||||||
|
* @param api
|
||||||
|
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
|
||||||
|
* @param mv
|
||||||
|
* the module visitor to which this visitor must delegate method
|
||||||
|
* calls. May be null.
|
||||||
|
*/
|
||||||
|
public ModuleVisitor(final int api, final ModuleVisitor mv) {
|
||||||
|
if (api != Opcodes.ASM6) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
this.api = api;
|
||||||
|
this.mv = mv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit the main class of the current module.
|
||||||
|
*
|
||||||
|
* @param mainClass the internal name of the main class of the current module.
|
||||||
|
*/
|
||||||
|
public void visitMainClass(String mainClass) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitMainClass(mainClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit a package of the current module.
|
||||||
|
*
|
||||||
|
* @param packaze the qualified name of a package.
|
||||||
|
*/
|
||||||
|
public void visitPackage(String packaze) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitPackage(packaze);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits a dependence of the current module.
|
||||||
|
*
|
||||||
|
* @param module the qualified name of the dependence.
|
||||||
|
* @param access the access flag of the dependence among
|
||||||
|
* ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC
|
||||||
|
* and ACC_MANDATED.
|
||||||
|
* @param version the module version at compile time or null.
|
||||||
|
*/
|
||||||
|
public void visitRequire(String module, int access, String version) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitRequire(module, access, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit an exported package of the current module.
|
||||||
|
*
|
||||||
|
* @param packaze the qualified name of the exported package.
|
||||||
|
* @param access the access flag of the exported package,
|
||||||
|
* valid values are among {@code ACC_SYNTHETIC} and
|
||||||
|
* {@code ACC_MANDATED}.
|
||||||
|
* @param modules the qualified names of the modules that can access to
|
||||||
|
* the public classes of the exported package or
|
||||||
|
* <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
public void visitExport(String packaze, int access, String... modules) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitExport(packaze, access, modules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit an open package of the current module.
|
||||||
|
*
|
||||||
|
* @param packaze the qualified name of the opened package.
|
||||||
|
* @param access the access flag of the opened package,
|
||||||
|
* valid values are among {@code ACC_SYNTHETIC} and
|
||||||
|
* {@code ACC_MANDATED}.
|
||||||
|
* @param modules the qualified names of the modules that can use deep
|
||||||
|
* reflection to the classes of the open package or
|
||||||
|
* <tt>null</tt>.
|
||||||
|
*/
|
||||||
|
public void visitOpen(String packaze, int access, String... modules) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitOpen(packaze, access, modules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit a service used by the current module.
|
||||||
|
* The name must be the internal name of an interface or a class.
|
||||||
|
*
|
||||||
|
* @param service the internal name of the service.
|
||||||
|
*/
|
||||||
|
public void visitUse(String service) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitUse(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit an implementation of a service.
|
||||||
|
*
|
||||||
|
* @param service the internal name of the service
|
||||||
|
* @param providers the internal names of the implementations
|
||||||
|
* of the service (there is at least one provider).
|
||||||
|
*/
|
||||||
|
public void visitProvide(String service, String... providers) {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitProvide(service, providers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the end of the module. This method, which is the last one to be
|
||||||
|
* called, is used to inform the visitor that everything have been visited.
|
||||||
|
*/
|
||||||
|
public void visitEnd() {
|
||||||
|
if (mv != null) {
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
322
src/main/java/org/redkale/asm/ModuleWriter.java
Normal file
322
src/main/java/org/redkale/asm/ModuleWriter.java
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi Forax
|
||||||
|
*/
|
||||||
|
final class ModuleWriter extends ModuleVisitor {
|
||||||
|
/**
|
||||||
|
* The class writer to which this Module attribute must be added.
|
||||||
|
*/
|
||||||
|
private final ClassWriter cw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* size in byte of the Module attribute.
|
||||||
|
*/
|
||||||
|
int size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of attributes associated with the current module
|
||||||
|
* (Version, ConcealPackages, etc)
|
||||||
|
*/
|
||||||
|
int attributeCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size in bytes of the attributes associated with the current module
|
||||||
|
*/
|
||||||
|
int attributesSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* module name index in the constant pool
|
||||||
|
*/
|
||||||
|
private final int name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* module access flags
|
||||||
|
*/
|
||||||
|
private final int access;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* module version index in the constant pool or 0
|
||||||
|
*/
|
||||||
|
private final int version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* module main class index in the constant pool or 0
|
||||||
|
*/
|
||||||
|
private int mainClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of packages
|
||||||
|
*/
|
||||||
|
private int packageCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The packages in bytecode form. This byte vector only contains
|
||||||
|
* the items themselves, the number of items is store in packageCount
|
||||||
|
*/
|
||||||
|
private ByteVector packages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of requires items
|
||||||
|
*/
|
||||||
|
private int requireCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The requires items in bytecode form. This byte vector only contains
|
||||||
|
* the items themselves, the number of items is store in requireCount
|
||||||
|
*/
|
||||||
|
private ByteVector requires;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of exports items
|
||||||
|
*/
|
||||||
|
private int exportCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exports items in bytecode form. This byte vector only contains
|
||||||
|
* the items themselves, the number of items is store in exportCount
|
||||||
|
*/
|
||||||
|
private ByteVector exports;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of opens items
|
||||||
|
*/
|
||||||
|
private int openCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opens items in bytecode form. This byte vector only contains
|
||||||
|
* the items themselves, the number of items is store in openCount
|
||||||
|
*/
|
||||||
|
private ByteVector opens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of uses items
|
||||||
|
*/
|
||||||
|
private int useCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uses items in bytecode form. This byte vector only contains
|
||||||
|
* the items themselves, the number of items is store in useCount
|
||||||
|
*/
|
||||||
|
private ByteVector uses;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of provides items
|
||||||
|
*/
|
||||||
|
private int provideCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uses provides in bytecode form. This byte vector only contains
|
||||||
|
* the items themselves, the number of items is store in provideCount
|
||||||
|
*/
|
||||||
|
private ByteVector provides;
|
||||||
|
|
||||||
|
ModuleWriter(final ClassWriter cw, final int name,
|
||||||
|
final int access, final int version) {
|
||||||
|
super(Opcodes.ASM6);
|
||||||
|
this.cw = cw;
|
||||||
|
this.size = 16; // name + access + version + 5 counts
|
||||||
|
this.name = name;
|
||||||
|
this.access = access;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMainClass(String mainClass) {
|
||||||
|
if (this.mainClass == 0) { // protect against several calls to visitMainClass
|
||||||
|
cw.newUTF8("ModuleMainClass");
|
||||||
|
attributeCount++;
|
||||||
|
attributesSize += 8;
|
||||||
|
}
|
||||||
|
this.mainClass = cw.newClass(mainClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitPackage(String packaze) {
|
||||||
|
if (packages == null) {
|
||||||
|
// protect against several calls to visitPackage
|
||||||
|
cw.newUTF8("ModulePackages");
|
||||||
|
packages = new ByteVector();
|
||||||
|
attributeCount++;
|
||||||
|
attributesSize += 8;
|
||||||
|
}
|
||||||
|
packages.putShort(cw.newPackage(packaze));
|
||||||
|
packageCount++;
|
||||||
|
attributesSize += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitRequire(String module, int access, String version) {
|
||||||
|
if (requires == null) {
|
||||||
|
requires = new ByteVector();
|
||||||
|
}
|
||||||
|
requires.putShort(cw.newModule(module))
|
||||||
|
.putShort(access)
|
||||||
|
.putShort(version == null? 0: cw.newUTF8(version));
|
||||||
|
requireCount++;
|
||||||
|
size += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitExport(String packaze, int access, String... modules) {
|
||||||
|
if (exports == null) {
|
||||||
|
exports = new ByteVector();
|
||||||
|
}
|
||||||
|
exports.putShort(cw.newPackage(packaze)).putShort(access);
|
||||||
|
if (modules == null) {
|
||||||
|
exports.putShort(0);
|
||||||
|
size += 6;
|
||||||
|
} else {
|
||||||
|
exports.putShort(modules.length);
|
||||||
|
for(String module: modules) {
|
||||||
|
exports.putShort(cw.newModule(module));
|
||||||
|
}
|
||||||
|
size += 6 + 2 * modules.length;
|
||||||
|
}
|
||||||
|
exportCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitOpen(String packaze, int access, String... modules) {
|
||||||
|
if (opens == null) {
|
||||||
|
opens = new ByteVector();
|
||||||
|
}
|
||||||
|
opens.putShort(cw.newPackage(packaze)).putShort(access);
|
||||||
|
if (modules == null) {
|
||||||
|
opens.putShort(0);
|
||||||
|
size += 6;
|
||||||
|
} else {
|
||||||
|
opens.putShort(modules.length);
|
||||||
|
for(String module: modules) {
|
||||||
|
opens.putShort(cw.newModule(module));
|
||||||
|
}
|
||||||
|
size += 6 + 2 * modules.length;
|
||||||
|
}
|
||||||
|
openCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitUse(String service) {
|
||||||
|
if (uses == null) {
|
||||||
|
uses = new ByteVector();
|
||||||
|
}
|
||||||
|
uses.putShort(cw.newClass(service));
|
||||||
|
useCount++;
|
||||||
|
size += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitProvide(String service, String... providers) {
|
||||||
|
if (provides == null) {
|
||||||
|
provides = new ByteVector();
|
||||||
|
}
|
||||||
|
provides.putShort(cw.newClass(service));
|
||||||
|
provides.putShort(providers.length);
|
||||||
|
for(String provider: providers) {
|
||||||
|
provides.putShort(cw.newClass(provider));
|
||||||
|
}
|
||||||
|
provideCount++;
|
||||||
|
size += 4 + 2 * providers.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEnd() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void putAttributes(ByteVector out) {
|
||||||
|
if (mainClass != 0) {
|
||||||
|
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
|
||||||
|
}
|
||||||
|
if (packages != null) {
|
||||||
|
out.putShort(cw.newUTF8("ModulePackages"))
|
||||||
|
.putInt(2 + 2 * packageCount)
|
||||||
|
.putShort(packageCount)
|
||||||
|
.putByteArray(packages.data, 0, packages.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void put(ByteVector out) {
|
||||||
|
out.putInt(size);
|
||||||
|
out.putShort(name).putShort(access).putShort(version);
|
||||||
|
out.putShort(requireCount);
|
||||||
|
if (requires != null) {
|
||||||
|
out.putByteArray(requires.data, 0, requires.length);
|
||||||
|
}
|
||||||
|
out.putShort(exportCount);
|
||||||
|
if (exports != null) {
|
||||||
|
out.putByteArray(exports.data, 0, exports.length);
|
||||||
|
}
|
||||||
|
out.putShort(openCount);
|
||||||
|
if (opens != null) {
|
||||||
|
out.putByteArray(opens.data, 0, opens.length);
|
||||||
|
}
|
||||||
|
out.putShort(useCount);
|
||||||
|
if (uses != null) {
|
||||||
|
out.putByteArray(uses.data, 0, uses.length);
|
||||||
|
}
|
||||||
|
out.putShort(provideCount);
|
||||||
|
if (provides != null) {
|
||||||
|
out.putByteArray(provides.data, 0, provides.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
402
src/main/java/org/redkale/asm/Opcodes.java
Normal file
402
src/main/java/org/redkale/asm/Opcodes.java
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the JVM opcodes, access flags and array type codes. This interface
|
||||||
|
* does not define all the JVM opcodes because some opcodes are automatically
|
||||||
|
* handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
|
||||||
|
* by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n
|
||||||
|
* opcodes are therefore not defined in this interface. Likewise for LDC,
|
||||||
|
* automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and
|
||||||
|
* JSR_W.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
* @author Eugene Kuleshov
|
||||||
|
*/
|
||||||
|
public interface Opcodes {
|
||||||
|
|
||||||
|
// ASM API versions
|
||||||
|
int ASM4 = 4 << 16 | 0 << 8;
|
||||||
|
int ASM5 = 5 << 16 | 0 << 8;
|
||||||
|
int ASM6 = 6 << 16 | 0 << 8;
|
||||||
|
|
||||||
|
// versions
|
||||||
|
|
||||||
|
int V1_1 = 3 << 16 | 45;
|
||||||
|
int V1_2 = 0 << 16 | 46;
|
||||||
|
int V1_3 = 0 << 16 | 47;
|
||||||
|
int V1_4 = 0 << 16 | 48;
|
||||||
|
int V1_5 = 0 << 16 | 49;
|
||||||
|
int V1_6 = 0 << 16 | 50;
|
||||||
|
int V1_7 = 0 << 16 | 51;
|
||||||
|
int V1_8 = 0 << 16 | 52;
|
||||||
|
int V9 = 0 << 16 | 53;
|
||||||
|
int V10 = 0 << 16 | 54;
|
||||||
|
int V11 = 0 << 16 | 55;
|
||||||
|
|
||||||
|
// access flags
|
||||||
|
|
||||||
|
int ACC_PUBLIC = 0x0001; // class, field, method
|
||||||
|
int ACC_PRIVATE = 0x0002; // class, field, method
|
||||||
|
int ACC_PROTECTED = 0x0004; // class, field, method
|
||||||
|
int ACC_STATIC = 0x0008; // field, method
|
||||||
|
int ACC_FINAL = 0x0010; // class, field, method, parameter
|
||||||
|
int ACC_SUPER = 0x0020; // class
|
||||||
|
int ACC_SYNCHRONIZED = 0x0020; // method
|
||||||
|
int ACC_OPEN = 0x0020; // module
|
||||||
|
int ACC_TRANSITIVE = 0x0020; // module requires
|
||||||
|
int ACC_VOLATILE = 0x0040; // field
|
||||||
|
int ACC_BRIDGE = 0x0040; // method
|
||||||
|
int ACC_STATIC_PHASE = 0x0040; // module requires
|
||||||
|
int ACC_VARARGS = 0x0080; // method
|
||||||
|
int ACC_TRANSIENT = 0x0080; // field
|
||||||
|
int ACC_NATIVE = 0x0100; // method
|
||||||
|
int ACC_INTERFACE = 0x0200; // class
|
||||||
|
int ACC_ABSTRACT = 0x0400; // class, method
|
||||||
|
int ACC_STRICT = 0x0800; // method
|
||||||
|
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
|
||||||
|
int ACC_ANNOTATION = 0x2000; // class
|
||||||
|
int ACC_ENUM = 0x4000; // class(?) field inner
|
||||||
|
int ACC_MANDATED = 0x8000; // parameter, module, module *
|
||||||
|
int ACC_MODULE = 0x8000; // class
|
||||||
|
|
||||||
|
|
||||||
|
// ASM specific pseudo access flags
|
||||||
|
|
||||||
|
int ACC_DEPRECATED = 0x20000; // class, field, method
|
||||||
|
|
||||||
|
// types for NEWARRAY
|
||||||
|
|
||||||
|
int T_BOOLEAN = 4;
|
||||||
|
int T_CHAR = 5;
|
||||||
|
int T_FLOAT = 6;
|
||||||
|
int T_DOUBLE = 7;
|
||||||
|
int T_BYTE = 8;
|
||||||
|
int T_SHORT = 9;
|
||||||
|
int T_INT = 10;
|
||||||
|
int T_LONG = 11;
|
||||||
|
|
||||||
|
// tags for Handle
|
||||||
|
|
||||||
|
int H_GETFIELD = 1;
|
||||||
|
int H_GETSTATIC = 2;
|
||||||
|
int H_PUTFIELD = 3;
|
||||||
|
int H_PUTSTATIC = 4;
|
||||||
|
int H_INVOKEVIRTUAL = 5;
|
||||||
|
int H_INVOKESTATIC = 6;
|
||||||
|
int H_INVOKESPECIAL = 7;
|
||||||
|
int H_NEWINVOKESPECIAL = 8;
|
||||||
|
int H_INVOKEINTERFACE = 9;
|
||||||
|
|
||||||
|
// stack map frame types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
|
||||||
|
*/
|
||||||
|
int F_NEW = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a compressed frame with complete frame data.
|
||||||
|
*/
|
||||||
|
int F_FULL = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a compressed frame where locals are the same as the locals in
|
||||||
|
* the previous frame, except that additional 1-3 locals are defined, and
|
||||||
|
* with an empty stack.
|
||||||
|
*/
|
||||||
|
int F_APPEND = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a compressed frame where locals are the same as the locals in
|
||||||
|
* the previous frame, except that the last 1-3 locals are absent and with
|
||||||
|
* an empty stack.
|
||||||
|
*/
|
||||||
|
int F_CHOP = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a compressed frame with exactly the same locals as the
|
||||||
|
* previous frame and with an empty stack.
|
||||||
|
*/
|
||||||
|
int F_SAME = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a compressed frame with exactly the same locals as the
|
||||||
|
* previous frame and with a single value on the stack.
|
||||||
|
*/
|
||||||
|
int F_SAME1 = 4;
|
||||||
|
|
||||||
|
// Do not try to change the following code to use auto-boxing,
|
||||||
|
// these values are compared by reference and not by value
|
||||||
|
// The constructor of Integer was deprecated in 9
|
||||||
|
// but we are stuck with it by backward compatibility
|
||||||
|
@SuppressWarnings("deprecation") Integer TOP = new Integer(0);
|
||||||
|
@SuppressWarnings("deprecation") Integer INTEGER = new Integer(1);
|
||||||
|
@SuppressWarnings("deprecation") Integer FLOAT = new Integer(2);
|
||||||
|
@SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3);
|
||||||
|
@SuppressWarnings("deprecation") Integer LONG = new Integer(4);
|
||||||
|
@SuppressWarnings("deprecation") Integer NULL = new Integer(5);
|
||||||
|
@SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6);
|
||||||
|
|
||||||
|
// opcodes // visit method (- = idem)
|
||||||
|
|
||||||
|
int NOP = 0; // visitInsn
|
||||||
|
int ACONST_NULL = 1; // -
|
||||||
|
int ICONST_M1 = 2; // -
|
||||||
|
int ICONST_0 = 3; // -
|
||||||
|
int ICONST_1 = 4; // -
|
||||||
|
int ICONST_2 = 5; // -
|
||||||
|
int ICONST_3 = 6; // -
|
||||||
|
int ICONST_4 = 7; // -
|
||||||
|
int ICONST_5 = 8; // -
|
||||||
|
int LCONST_0 = 9; // -
|
||||||
|
int LCONST_1 = 10; // -
|
||||||
|
int FCONST_0 = 11; // -
|
||||||
|
int FCONST_1 = 12; // -
|
||||||
|
int FCONST_2 = 13; // -
|
||||||
|
int DCONST_0 = 14; // -
|
||||||
|
int DCONST_1 = 15; // -
|
||||||
|
int BIPUSH = 16; // visitIntInsn
|
||||||
|
int SIPUSH = 17; // -
|
||||||
|
int LDC = 18; // visitLdcInsn
|
||||||
|
// int LDC_W = 19; // -
|
||||||
|
// int LDC2_W = 20; // -
|
||||||
|
int ILOAD = 21; // visitVarInsn
|
||||||
|
int LLOAD = 22; // -
|
||||||
|
int FLOAD = 23; // -
|
||||||
|
int DLOAD = 24; // -
|
||||||
|
int ALOAD = 25; // -
|
||||||
|
// int ILOAD_0 = 26; // -
|
||||||
|
// int ILOAD_1 = 27; // -
|
||||||
|
// int ILOAD_2 = 28; // -
|
||||||
|
// int ILOAD_3 = 29; // -
|
||||||
|
// int LLOAD_0 = 30; // -
|
||||||
|
// int LLOAD_1 = 31; // -
|
||||||
|
// int LLOAD_2 = 32; // -
|
||||||
|
// int LLOAD_3 = 33; // -
|
||||||
|
// int FLOAD_0 = 34; // -
|
||||||
|
// int FLOAD_1 = 35; // -
|
||||||
|
// int FLOAD_2 = 36; // -
|
||||||
|
// int FLOAD_3 = 37; // -
|
||||||
|
// int DLOAD_0 = 38; // -
|
||||||
|
// int DLOAD_1 = 39; // -
|
||||||
|
// int DLOAD_2 = 40; // -
|
||||||
|
// int DLOAD_3 = 41; // -
|
||||||
|
// int ALOAD_0 = 42; // -
|
||||||
|
// int ALOAD_1 = 43; // -
|
||||||
|
// int ALOAD_2 = 44; // -
|
||||||
|
// int ALOAD_3 = 45; // -
|
||||||
|
int IALOAD = 46; // visitInsn
|
||||||
|
int LALOAD = 47; // -
|
||||||
|
int FALOAD = 48; // -
|
||||||
|
int DALOAD = 49; // -
|
||||||
|
int AALOAD = 50; // -
|
||||||
|
int BALOAD = 51; // -
|
||||||
|
int CALOAD = 52; // -
|
||||||
|
int SALOAD = 53; // -
|
||||||
|
int ISTORE = 54; // visitVarInsn
|
||||||
|
int LSTORE = 55; // -
|
||||||
|
int FSTORE = 56; // -
|
||||||
|
int DSTORE = 57; // -
|
||||||
|
int ASTORE = 58; // -
|
||||||
|
// int ISTORE_0 = 59; // -
|
||||||
|
// int ISTORE_1 = 60; // -
|
||||||
|
// int ISTORE_2 = 61; // -
|
||||||
|
// int ISTORE_3 = 62; // -
|
||||||
|
// int LSTORE_0 = 63; // -
|
||||||
|
// int LSTORE_1 = 64; // -
|
||||||
|
// int LSTORE_2 = 65; // -
|
||||||
|
// int LSTORE_3 = 66; // -
|
||||||
|
// int FSTORE_0 = 67; // -
|
||||||
|
// int FSTORE_1 = 68; // -
|
||||||
|
// int FSTORE_2 = 69; // -
|
||||||
|
// int FSTORE_3 = 70; // -
|
||||||
|
// int DSTORE_0 = 71; // -
|
||||||
|
// int DSTORE_1 = 72; // -
|
||||||
|
// int DSTORE_2 = 73; // -
|
||||||
|
// int DSTORE_3 = 74; // -
|
||||||
|
// int ASTORE_0 = 75; // -
|
||||||
|
// int ASTORE_1 = 76; // -
|
||||||
|
// int ASTORE_2 = 77; // -
|
||||||
|
// int ASTORE_3 = 78; // -
|
||||||
|
int IASTORE = 79; // visitInsn
|
||||||
|
int LASTORE = 80; // -
|
||||||
|
int FASTORE = 81; // -
|
||||||
|
int DASTORE = 82; // -
|
||||||
|
int AASTORE = 83; // -
|
||||||
|
int BASTORE = 84; // -
|
||||||
|
int CASTORE = 85; // -
|
||||||
|
int SASTORE = 86; // -
|
||||||
|
int POP = 87; // -
|
||||||
|
int POP2 = 88; // -
|
||||||
|
int DUP = 89; // -
|
||||||
|
int DUP_X1 = 90; // -
|
||||||
|
int DUP_X2 = 91; // -
|
||||||
|
int DUP2 = 92; // -
|
||||||
|
int DUP2_X1 = 93; // -
|
||||||
|
int DUP2_X2 = 94; // -
|
||||||
|
int SWAP = 95; // -
|
||||||
|
int IADD = 96; // -
|
||||||
|
int LADD = 97; // -
|
||||||
|
int FADD = 98; // -
|
||||||
|
int DADD = 99; // -
|
||||||
|
int ISUB = 100; // -
|
||||||
|
int LSUB = 101; // -
|
||||||
|
int FSUB = 102; // -
|
||||||
|
int DSUB = 103; // -
|
||||||
|
int IMUL = 104; // -
|
||||||
|
int LMUL = 105; // -
|
||||||
|
int FMUL = 106; // -
|
||||||
|
int DMUL = 107; // -
|
||||||
|
int IDIV = 108; // -
|
||||||
|
int LDIV = 109; // -
|
||||||
|
int FDIV = 110; // -
|
||||||
|
int DDIV = 111; // -
|
||||||
|
int IREM = 112; // -
|
||||||
|
int LREM = 113; // -
|
||||||
|
int FREM = 114; // -
|
||||||
|
int DREM = 115; // -
|
||||||
|
int INEG = 116; // -
|
||||||
|
int LNEG = 117; // -
|
||||||
|
int FNEG = 118; // -
|
||||||
|
int DNEG = 119; // -
|
||||||
|
int ISHL = 120; // -
|
||||||
|
int LSHL = 121; // -
|
||||||
|
int ISHR = 122; // -
|
||||||
|
int LSHR = 123; // -
|
||||||
|
int IUSHR = 124; // -
|
||||||
|
int LUSHR = 125; // -
|
||||||
|
int IAND = 126; // -
|
||||||
|
int LAND = 127; // -
|
||||||
|
int IOR = 128; // -
|
||||||
|
int LOR = 129; // -
|
||||||
|
int IXOR = 130; // -
|
||||||
|
int LXOR = 131; // -
|
||||||
|
int IINC = 132; // visitIincInsn
|
||||||
|
int I2L = 133; // visitInsn
|
||||||
|
int I2F = 134; // -
|
||||||
|
int I2D = 135; // -
|
||||||
|
int L2I = 136; // -
|
||||||
|
int L2F = 137; // -
|
||||||
|
int L2D = 138; // -
|
||||||
|
int F2I = 139; // -
|
||||||
|
int F2L = 140; // -
|
||||||
|
int F2D = 141; // -
|
||||||
|
int D2I = 142; // -
|
||||||
|
int D2L = 143; // -
|
||||||
|
int D2F = 144; // -
|
||||||
|
int I2B = 145; // -
|
||||||
|
int I2C = 146; // -
|
||||||
|
int I2S = 147; // -
|
||||||
|
int LCMP = 148; // -
|
||||||
|
int FCMPL = 149; // -
|
||||||
|
int FCMPG = 150; // -
|
||||||
|
int DCMPL = 151; // -
|
||||||
|
int DCMPG = 152; // -
|
||||||
|
int IFEQ = 153; // visitJumpInsn
|
||||||
|
int IFNE = 154; // -
|
||||||
|
int IFLT = 155; // -
|
||||||
|
int IFGE = 156; // -
|
||||||
|
int IFGT = 157; // -
|
||||||
|
int IFLE = 158; // -
|
||||||
|
int IF_ICMPEQ = 159; // -
|
||||||
|
int IF_ICMPNE = 160; // -
|
||||||
|
int IF_ICMPLT = 161; // -
|
||||||
|
int IF_ICMPGE = 162; // -
|
||||||
|
int IF_ICMPGT = 163; // -
|
||||||
|
int IF_ICMPLE = 164; // -
|
||||||
|
int IF_ACMPEQ = 165; // -
|
||||||
|
int IF_ACMPNE = 166; // -
|
||||||
|
int GOTO = 167; // -
|
||||||
|
int JSR = 168; // -
|
||||||
|
int RET = 169; // visitVarInsn
|
||||||
|
int TABLESWITCH = 170; // visiTableSwitchInsn
|
||||||
|
int LOOKUPSWITCH = 171; // visitLookupSwitch
|
||||||
|
int IRETURN = 172; // visitInsn
|
||||||
|
int LRETURN = 173; // -
|
||||||
|
int FRETURN = 174; // -
|
||||||
|
int DRETURN = 175; // -
|
||||||
|
int ARETURN = 176; // -
|
||||||
|
int RETURN = 177; // -
|
||||||
|
int GETSTATIC = 178; // visitFieldInsn
|
||||||
|
int PUTSTATIC = 179; // -
|
||||||
|
int GETFIELD = 180; // -
|
||||||
|
int PUTFIELD = 181; // -
|
||||||
|
int INVOKEVIRTUAL = 182; // visitMethodInsn
|
||||||
|
int INVOKESPECIAL = 183; // -
|
||||||
|
int INVOKESTATIC = 184; // -
|
||||||
|
int INVOKEINTERFACE = 185; // -
|
||||||
|
int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
|
||||||
|
int NEW = 187; // visitTypeInsn
|
||||||
|
int NEWARRAY = 188; // visitIntInsn
|
||||||
|
int ANEWARRAY = 189; // visitTypeInsn
|
||||||
|
int ARRAYLENGTH = 190; // visitInsn
|
||||||
|
int ATHROW = 191; // -
|
||||||
|
int CHECKCAST = 192; // visitTypeInsn
|
||||||
|
int INSTANCEOF = 193; // -
|
||||||
|
int MONITORENTER = 194; // visitInsn
|
||||||
|
int MONITOREXIT = 195; // -
|
||||||
|
// int WIDE = 196; // NOT VISITED
|
||||||
|
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
|
||||||
|
int IFNULL = 198; // visitJumpInsn
|
||||||
|
int IFNONNULL = 199; // -
|
||||||
|
// int GOTO_W = 200; // -
|
||||||
|
// int JSR_W = 201; // -
|
||||||
|
}
|
||||||
934
src/main/java/org/redkale/asm/Type.java
Normal file
934
src/main/java/org/redkale/asm/Type.java
Normal file
@@ -0,0 +1,934 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Java field or method type. This class can be used to make it easier to
|
||||||
|
* manipulate type and method descriptors.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
* @author Chris Nokleberg
|
||||||
|
*/
|
||||||
|
public class Type {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int VOID = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int BOOLEAN = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int CHAR = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int BYTE = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int SHORT = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int INT = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int FLOAT = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int LONG = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int DOUBLE = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of array reference types. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int ARRAY = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of object reference types. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int OBJECT = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of method types. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public static final int METHOD = 11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>void</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
|
||||||
|
| (5 << 16) | (0 << 8) | 0, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>boolean</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
|
||||||
|
| (0 << 16) | (5 << 8) | 1, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>char</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
|
||||||
|
| (0 << 16) | (6 << 8) | 1, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>byte</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
|
||||||
|
| (0 << 16) | (5 << 8) | 1, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>short</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
|
||||||
|
| (0 << 16) | (7 << 8) | 1, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>int</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
|
||||||
|
| (0 << 16) | (0 << 8) | 1, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>float</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
|
||||||
|
| (2 << 16) | (2 << 8) | 1, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>long</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
|
||||||
|
| (1 << 16) | (1 << 8) | 2, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <tt>double</tt> type.
|
||||||
|
*/
|
||||||
|
public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
|
||||||
|
| (3 << 16) | (3 << 8) | 2, 1);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Fields
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of this Java type.
|
||||||
|
*/
|
||||||
|
private final int sort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffer containing the internal name of this Java type. This field is
|
||||||
|
* only used for reference types.
|
||||||
|
*/
|
||||||
|
private final char[] buf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset of the internal name of this Java type in {@link #buf buf} or,
|
||||||
|
* for primitive types, the size, descriptor and getOpcode offsets for this
|
||||||
|
* type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
|
||||||
|
* for IALOAD or IASTORE, byte 3 the offset for all other instructions).
|
||||||
|
*/
|
||||||
|
private final int off;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the internal name of this Java type.
|
||||||
|
*/
|
||||||
|
private final int len;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constructors
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a reference type.
|
||||||
|
*
|
||||||
|
* @param sort
|
||||||
|
* the sort of the reference type to be constructed.
|
||||||
|
* @param buf
|
||||||
|
* a buffer containing the descriptor of the previous type.
|
||||||
|
* @param off
|
||||||
|
* the offset of this descriptor in the previous buffer.
|
||||||
|
* @param len
|
||||||
|
* the length of this descriptor.
|
||||||
|
*/
|
||||||
|
private Type(final int sort, final char[] buf, final int off, final int len) {
|
||||||
|
this.sort = sort;
|
||||||
|
this.buf = buf;
|
||||||
|
this.off = off;
|
||||||
|
this.len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java type corresponding to the given type descriptor.
|
||||||
|
*
|
||||||
|
* @param typeDescriptor
|
||||||
|
* a field or method type descriptor.
|
||||||
|
* @return the Java type corresponding to the given type descriptor.
|
||||||
|
*/
|
||||||
|
public static Type getType(final String typeDescriptor) {
|
||||||
|
return getType(typeDescriptor.toCharArray(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java type corresponding to the given internal name.
|
||||||
|
*
|
||||||
|
* @param internalName
|
||||||
|
* an internal name.
|
||||||
|
* @return the Java type corresponding to the given internal name.
|
||||||
|
*/
|
||||||
|
public static Type getObjectType(final String internalName) {
|
||||||
|
char[] buf = internalName.toCharArray();
|
||||||
|
return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java type corresponding to the given method descriptor.
|
||||||
|
* Equivalent to <code>Type.getType(methodDescriptor)</code>.
|
||||||
|
*
|
||||||
|
* @param methodDescriptor
|
||||||
|
* a method descriptor.
|
||||||
|
* @return the Java type corresponding to the given method descriptor.
|
||||||
|
*/
|
||||||
|
public static Type getMethodType(final String methodDescriptor) {
|
||||||
|
return getType(methodDescriptor.toCharArray(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java method type corresponding to the given argument and
|
||||||
|
* return types.
|
||||||
|
*
|
||||||
|
* @param returnType
|
||||||
|
* the return type of the method.
|
||||||
|
* @param argumentTypes
|
||||||
|
* the argument types of the method.
|
||||||
|
* @return the Java type corresponding to the given argument and return
|
||||||
|
* types.
|
||||||
|
*/
|
||||||
|
public static Type getMethodType(final Type returnType,
|
||||||
|
final Type... argumentTypes) {
|
||||||
|
return getType(getMethodDescriptor(returnType, argumentTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java type corresponding to the given class.
|
||||||
|
*
|
||||||
|
* @param c
|
||||||
|
* a class.
|
||||||
|
* @return the Java type corresponding to the given class.
|
||||||
|
*/
|
||||||
|
public static Type getType(final Class<?> c) {
|
||||||
|
if (c.isPrimitive()) {
|
||||||
|
if (c == Integer.TYPE) {
|
||||||
|
return INT_TYPE;
|
||||||
|
} else if (c == Void.TYPE) {
|
||||||
|
return VOID_TYPE;
|
||||||
|
} else if (c == Boolean.TYPE) {
|
||||||
|
return BOOLEAN_TYPE;
|
||||||
|
} else if (c == Byte.TYPE) {
|
||||||
|
return BYTE_TYPE;
|
||||||
|
} else if (c == Character.TYPE) {
|
||||||
|
return CHAR_TYPE;
|
||||||
|
} else if (c == Short.TYPE) {
|
||||||
|
return SHORT_TYPE;
|
||||||
|
} else if (c == Double.TYPE) {
|
||||||
|
return DOUBLE_TYPE;
|
||||||
|
} else if (c == Float.TYPE) {
|
||||||
|
return FLOAT_TYPE;
|
||||||
|
} else /* if (c == Long.TYPE) */{
|
||||||
|
return LONG_TYPE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return getType(getDescriptor(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java method type corresponding to the given constructor.
|
||||||
|
*
|
||||||
|
* @param c
|
||||||
|
* a {@link Constructor Constructor} object.
|
||||||
|
* @return the Java method type corresponding to the given constructor.
|
||||||
|
*/
|
||||||
|
public static Type getType(final Constructor<?> c) {
|
||||||
|
return getType(getConstructorDescriptor(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java method type corresponding to the given method.
|
||||||
|
*
|
||||||
|
* @param m
|
||||||
|
* a {@link Method Method} object.
|
||||||
|
* @return the Java method type corresponding to the given method.
|
||||||
|
*/
|
||||||
|
public static Type getType(final Method m) {
|
||||||
|
return getType(getMethodDescriptor(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java types corresponding to the argument types of the given
|
||||||
|
* method descriptor.
|
||||||
|
*
|
||||||
|
* @param methodDescriptor
|
||||||
|
* a method descriptor.
|
||||||
|
* @return the Java types corresponding to the argument types of the given
|
||||||
|
* method descriptor.
|
||||||
|
*/
|
||||||
|
public static Type[] getArgumentTypes(final String methodDescriptor) {
|
||||||
|
char[] buf = methodDescriptor.toCharArray();
|
||||||
|
int off = 1;
|
||||||
|
int size = 0;
|
||||||
|
while (true) {
|
||||||
|
char car = buf[off++];
|
||||||
|
if (car == ')') {
|
||||||
|
break;
|
||||||
|
} else if (car == 'L') {
|
||||||
|
while (buf[off++] != ';') {
|
||||||
|
}
|
||||||
|
++size;
|
||||||
|
} else if (car != '[') {
|
||||||
|
++size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type[] args = new Type[size];
|
||||||
|
off = 1;
|
||||||
|
size = 0;
|
||||||
|
while (buf[off] != ')') {
|
||||||
|
args[size] = getType(buf, off);
|
||||||
|
off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
|
||||||
|
size += 1;
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java types corresponding to the argument types of the given
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @param method
|
||||||
|
* a method.
|
||||||
|
* @return the Java types corresponding to the argument types of the given
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
public static Type[] getArgumentTypes(final Method method) {
|
||||||
|
Class<?>[] classes = method.getParameterTypes();
|
||||||
|
Type[] types = new Type[classes.length];
|
||||||
|
for (int i = classes.length - 1; i >= 0; --i) {
|
||||||
|
types[i] = getType(classes[i]);
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java type corresponding to the return type of the given
|
||||||
|
* method descriptor.
|
||||||
|
*
|
||||||
|
* @param methodDescriptor
|
||||||
|
* a method descriptor.
|
||||||
|
* @return the Java type corresponding to the return type of the given
|
||||||
|
* method descriptor.
|
||||||
|
*/
|
||||||
|
public static Type getReturnType(final String methodDescriptor) {
|
||||||
|
char[] buf = methodDescriptor.toCharArray();
|
||||||
|
int off = 1;
|
||||||
|
while (true) {
|
||||||
|
char car = buf[off++];
|
||||||
|
if (car == ')') {
|
||||||
|
return getType(buf, off);
|
||||||
|
} else if (car == 'L') {
|
||||||
|
while (buf[off++] != ';') {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java type corresponding to the return type of the given
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @param method
|
||||||
|
* a method.
|
||||||
|
* @return the Java type corresponding to the return type of the given
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
public static Type getReturnType(final Method method) {
|
||||||
|
return getType(method.getReturnType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the size of the arguments and of the return value of a method.
|
||||||
|
*
|
||||||
|
* @param desc
|
||||||
|
* the descriptor of a method.
|
||||||
|
* @return the size of the arguments of the method (plus one for the
|
||||||
|
* implicit this argument), argSize, and the size of its return
|
||||||
|
* value, retSize, packed into a single int i =
|
||||||
|
* <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to
|
||||||
|
* <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
|
||||||
|
*/
|
||||||
|
public static int getArgumentsAndReturnSizes(final String desc) {
|
||||||
|
int n = 1;
|
||||||
|
int c = 1;
|
||||||
|
while (true) {
|
||||||
|
char car = desc.charAt(c++);
|
||||||
|
if (car == ')') {
|
||||||
|
car = desc.charAt(c);
|
||||||
|
return n << 2
|
||||||
|
| (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
|
||||||
|
} else if (car == 'L') {
|
||||||
|
while (desc.charAt(c++) != ';') {
|
||||||
|
}
|
||||||
|
n += 1;
|
||||||
|
} else if (car == '[') {
|
||||||
|
while ((car = desc.charAt(c)) == '[') {
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
if (car == 'D' || car == 'J') {
|
||||||
|
n -= 1;
|
||||||
|
}
|
||||||
|
} else if (car == 'D' || car == 'J') {
|
||||||
|
n += 2;
|
||||||
|
} else {
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java type corresponding to the given type descriptor. For
|
||||||
|
* method descriptors, buf is supposed to contain nothing more than the
|
||||||
|
* descriptor itself.
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* a buffer containing a type descriptor.
|
||||||
|
* @param off
|
||||||
|
* the offset of this descriptor in the previous buffer.
|
||||||
|
* @return the Java type corresponding to the given type descriptor.
|
||||||
|
*/
|
||||||
|
private static Type getType(final char[] buf, final int off) {
|
||||||
|
int len;
|
||||||
|
switch (buf[off]) {
|
||||||
|
case 'V':
|
||||||
|
return VOID_TYPE;
|
||||||
|
case 'Z':
|
||||||
|
return BOOLEAN_TYPE;
|
||||||
|
case 'C':
|
||||||
|
return CHAR_TYPE;
|
||||||
|
case 'B':
|
||||||
|
return BYTE_TYPE;
|
||||||
|
case 'S':
|
||||||
|
return SHORT_TYPE;
|
||||||
|
case 'I':
|
||||||
|
return INT_TYPE;
|
||||||
|
case 'F':
|
||||||
|
return FLOAT_TYPE;
|
||||||
|
case 'J':
|
||||||
|
return LONG_TYPE;
|
||||||
|
case 'D':
|
||||||
|
return DOUBLE_TYPE;
|
||||||
|
case '[':
|
||||||
|
len = 1;
|
||||||
|
while (buf[off + len] == '[') {
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
if (buf[off + len] == 'L') {
|
||||||
|
++len;
|
||||||
|
while (buf[off + len] != ';') {
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Type(ARRAY, buf, off, len + 1);
|
||||||
|
case 'L':
|
||||||
|
len = 1;
|
||||||
|
while (buf[off + len] != ';') {
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
return new Type(OBJECT, buf, off + 1, len - 1);
|
||||||
|
// case '(':
|
||||||
|
default:
|
||||||
|
return new Type(METHOD, buf, off, buf.length - off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Accessors
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sort of this Java type.
|
||||||
|
*
|
||||||
|
* @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
|
||||||
|
* {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
|
||||||
|
* {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
|
||||||
|
* {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
|
||||||
|
* METHOD}.
|
||||||
|
*/
|
||||||
|
public int getSort() {
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of dimensions of this array type. This method should
|
||||||
|
* only be used for an array type.
|
||||||
|
*
|
||||||
|
* @return the number of dimensions of this array type.
|
||||||
|
*/
|
||||||
|
public int getDimensions() {
|
||||||
|
int i = 1;
|
||||||
|
while (buf[off + i] == '[') {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the elements of this array type. This method should
|
||||||
|
* only be used for an array type.
|
||||||
|
*
|
||||||
|
* @return Returns the type of the elements of this array type.
|
||||||
|
*/
|
||||||
|
public Type getElementType() {
|
||||||
|
return getType(buf, off + getDimensions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the binary name of the class corresponding to this type. This
|
||||||
|
* method must not be used on method types.
|
||||||
|
*
|
||||||
|
* @return the binary name of the class corresponding to this type.
|
||||||
|
*/
|
||||||
|
public String getClassName() {
|
||||||
|
switch (sort) {
|
||||||
|
case VOID:
|
||||||
|
return "void";
|
||||||
|
case BOOLEAN:
|
||||||
|
return "boolean";
|
||||||
|
case CHAR:
|
||||||
|
return "char";
|
||||||
|
case BYTE:
|
||||||
|
return "byte";
|
||||||
|
case SHORT:
|
||||||
|
return "short";
|
||||||
|
case INT:
|
||||||
|
return "int";
|
||||||
|
case FLOAT:
|
||||||
|
return "float";
|
||||||
|
case LONG:
|
||||||
|
return "long";
|
||||||
|
case DOUBLE:
|
||||||
|
return "double";
|
||||||
|
case ARRAY:
|
||||||
|
StringBuilder sb = new StringBuilder(getElementType().getClassName());
|
||||||
|
for (int i = getDimensions(); i > 0; --i) {
|
||||||
|
sb.append("[]");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
case OBJECT:
|
||||||
|
return new String(buf, off, len).replace('/', '.');
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the internal name of the class corresponding to this object or
|
||||||
|
* array type. The internal name of a class is its fully qualified name (as
|
||||||
|
* returned by Class.getName(), where '.' are replaced by '/'. This method
|
||||||
|
* should only be used for an object or array type.
|
||||||
|
*
|
||||||
|
* @return the internal name of the class corresponding to this object type.
|
||||||
|
*/
|
||||||
|
public String getInternalName() {
|
||||||
|
return new String(buf, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the argument types of methods of this type. This method should
|
||||||
|
* only be used for method types.
|
||||||
|
*
|
||||||
|
* @return the argument types of methods of this type.
|
||||||
|
*/
|
||||||
|
public Type[] getArgumentTypes() {
|
||||||
|
return getArgumentTypes(getDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the return type of methods of this type. This method should only
|
||||||
|
* be used for method types.
|
||||||
|
*
|
||||||
|
* @return the return type of methods of this type.
|
||||||
|
*/
|
||||||
|
public Type getReturnType() {
|
||||||
|
return getReturnType(getDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of the arguments and of the return value of methods of
|
||||||
|
* this type. This method should only be used for method types.
|
||||||
|
*
|
||||||
|
* @return the size of the arguments (plus one for the implicit this
|
||||||
|
* argument), argSize, and the size of the return value, retSize,
|
||||||
|
* packed into a single
|
||||||
|
* int i = <tt>(argSize << 2) | retSize</tt>
|
||||||
|
* (argSize is therefore equal to <tt>i >> 2</tt>,
|
||||||
|
* and retSize to <tt>i & 0x03</tt>).
|
||||||
|
*/
|
||||||
|
public int getArgumentsAndReturnSizes() {
|
||||||
|
return getArgumentsAndReturnSizes(getDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Conversion to type descriptors
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the descriptor corresponding to this Java type.
|
||||||
|
*
|
||||||
|
* @return the descriptor corresponding to this Java type.
|
||||||
|
*/
|
||||||
|
public String getDescriptor() {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
getDescriptor(buf);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the descriptor corresponding to the given argument and return
|
||||||
|
* types.
|
||||||
|
*
|
||||||
|
* @param returnType
|
||||||
|
* the return type of the method.
|
||||||
|
* @param argumentTypes
|
||||||
|
* the argument types of the method.
|
||||||
|
* @return the descriptor corresponding to the given argument and return
|
||||||
|
* types.
|
||||||
|
*/
|
||||||
|
public static String getMethodDescriptor(final Type returnType,
|
||||||
|
final Type... argumentTypes) {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append('(');
|
||||||
|
for (int i = 0; i < argumentTypes.length; ++i) {
|
||||||
|
argumentTypes[i].getDescriptor(buf);
|
||||||
|
}
|
||||||
|
buf.append(')');
|
||||||
|
returnType.getDescriptor(buf);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the descriptor corresponding to this Java type to the given
|
||||||
|
* string buffer.
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* the string buffer to which the descriptor must be appended.
|
||||||
|
*/
|
||||||
|
private void getDescriptor(final StringBuilder buf) {
|
||||||
|
if (this.buf == null) {
|
||||||
|
// descriptor is in byte 3 of 'off' for primitive types (buf ==
|
||||||
|
// null)
|
||||||
|
buf.append((char) ((off & 0xFF000000) >>> 24));
|
||||||
|
} else if (sort == OBJECT) {
|
||||||
|
buf.append('L');
|
||||||
|
buf.append(this.buf, off, len);
|
||||||
|
buf.append(';');
|
||||||
|
} else { // sort == ARRAY || sort == METHOD
|
||||||
|
buf.append(this.buf, off, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Direct conversion from classes to type descriptors,
|
||||||
|
// without intermediate Type objects
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the internal name of the given class. The internal name of a
|
||||||
|
* class is its fully qualified name, as returned by Class.getName(), where
|
||||||
|
* '.' are replaced by '/'.
|
||||||
|
*
|
||||||
|
* @param c
|
||||||
|
* an object or array class.
|
||||||
|
* @return the internal name of the given class.
|
||||||
|
*/
|
||||||
|
public static String getInternalName(final Class<?> c) {
|
||||||
|
return c.getName().replace('.', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the descriptor corresponding to the given Java type.
|
||||||
|
*
|
||||||
|
* @param c
|
||||||
|
* an object class, a primitive class or an array class.
|
||||||
|
* @return the descriptor corresponding to the given class.
|
||||||
|
*/
|
||||||
|
public static String getDescriptor(final Class<?> c) {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
getDescriptor(buf, c);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the descriptor corresponding to the given constructor.
|
||||||
|
*
|
||||||
|
* @param c
|
||||||
|
* a {@link Constructor Constructor} object.
|
||||||
|
* @return the descriptor of the given constructor.
|
||||||
|
*/
|
||||||
|
public static String getConstructorDescriptor(final Constructor<?> c) {
|
||||||
|
Class<?>[] parameters = c.getParameterTypes();
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append('(');
|
||||||
|
for (int i = 0; i < parameters.length; ++i) {
|
||||||
|
getDescriptor(buf, parameters[i]);
|
||||||
|
}
|
||||||
|
return buf.append(")V").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the descriptor corresponding to the given method.
|
||||||
|
*
|
||||||
|
* @param m
|
||||||
|
* a {@link Method Method} object.
|
||||||
|
* @return the descriptor of the given method.
|
||||||
|
*/
|
||||||
|
public static String getMethodDescriptor(final Method m) {
|
||||||
|
Class<?>[] parameters = m.getParameterTypes();
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append('(');
|
||||||
|
for (int i = 0; i < parameters.length; ++i) {
|
||||||
|
getDescriptor(buf, parameters[i]);
|
||||||
|
}
|
||||||
|
buf.append(')');
|
||||||
|
getDescriptor(buf, m.getReturnType());
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the descriptor of the given class to the given string buffer.
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* the string buffer to which the descriptor must be appended.
|
||||||
|
* @param c
|
||||||
|
* the class whose descriptor must be computed.
|
||||||
|
*/
|
||||||
|
private static void getDescriptor(final StringBuilder buf, final Class<?> c) {
|
||||||
|
Class<?> d = c;
|
||||||
|
while (true) {
|
||||||
|
if (d.isPrimitive()) {
|
||||||
|
char car;
|
||||||
|
if (d == Integer.TYPE) {
|
||||||
|
car = 'I';
|
||||||
|
} else if (d == Void.TYPE) {
|
||||||
|
car = 'V';
|
||||||
|
} else if (d == Boolean.TYPE) {
|
||||||
|
car = 'Z';
|
||||||
|
} else if (d == Byte.TYPE) {
|
||||||
|
car = 'B';
|
||||||
|
} else if (d == Character.TYPE) {
|
||||||
|
car = 'C';
|
||||||
|
} else if (d == Short.TYPE) {
|
||||||
|
car = 'S';
|
||||||
|
} else if (d == Double.TYPE) {
|
||||||
|
car = 'D';
|
||||||
|
} else if (d == Float.TYPE) {
|
||||||
|
car = 'F';
|
||||||
|
} else /* if (d == Long.TYPE) */{
|
||||||
|
car = 'J';
|
||||||
|
}
|
||||||
|
buf.append(car);
|
||||||
|
return;
|
||||||
|
} else if (d.isArray()) {
|
||||||
|
buf.append('[');
|
||||||
|
d = d.getComponentType();
|
||||||
|
} else {
|
||||||
|
buf.append('L');
|
||||||
|
String name = d.getName();
|
||||||
|
int len = name.length();
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
char car = name.charAt(i);
|
||||||
|
buf.append(car == '.' ? '/' : car);
|
||||||
|
}
|
||||||
|
buf.append(';');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Corresponding size and opcodes
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of values of this type. This method must not be used for
|
||||||
|
* method types.
|
||||||
|
*
|
||||||
|
* @return the size of values of this type, i.e., 2 for <tt>long</tt> and
|
||||||
|
* <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
|
||||||
|
*/
|
||||||
|
public int getSize() {
|
||||||
|
// the size is in byte 0 of 'off' for primitive types (buf == null)
|
||||||
|
return buf == null ? (off & 0xFF) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a JVM instruction opcode adapted to this Java type. This method
|
||||||
|
* must not be used for method types.
|
||||||
|
*
|
||||||
|
* @param opcode
|
||||||
|
* a JVM instruction opcode. This opcode must be one of ILOAD,
|
||||||
|
* ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
|
||||||
|
* ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
|
||||||
|
* @return an opcode that is similar to the given opcode, but adapted to
|
||||||
|
* this Java type. For example, if this type is <tt>float</tt> and
|
||||||
|
* <tt>opcode</tt> is IRETURN, this method returns FRETURN.
|
||||||
|
*/
|
||||||
|
public int getOpcode(final int opcode) {
|
||||||
|
if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
|
||||||
|
// the offset for IALOAD or IASTORE is in byte 1 of 'off' for
|
||||||
|
// primitive types (buf == null)
|
||||||
|
return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
|
||||||
|
} else {
|
||||||
|
// the offset for other instructions is in byte 2 of 'off' for
|
||||||
|
// primitive types (buf == null)
|
||||||
|
return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Equals, hashCode and toString
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the given object is equal to this type.
|
||||||
|
*
|
||||||
|
* @param o
|
||||||
|
* the object to be compared to this type.
|
||||||
|
* @return <tt>true</tt> if the given object is equal to this type.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof Type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Type t = (Type) o;
|
||||||
|
if (sort != t.sort) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sort >= ARRAY) {
|
||||||
|
if (len != t.len) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
|
||||||
|
if (buf[i] != t.buf[j]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hash code value for this type.
|
||||||
|
*
|
||||||
|
* @return a hash code value for this type.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hc = 13 * sort;
|
||||||
|
if (sort >= ARRAY) {
|
||||||
|
for (int i = off, end = i + len; i < end; i++) {
|
||||||
|
hc = 17 * (hc + buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this type.
|
||||||
|
*
|
||||||
|
* @return the descriptor of this type.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getDescriptor();
|
||||||
|
}
|
||||||
|
}
|
||||||
225
src/main/java/org/redkale/asm/TypePath.java
Normal file
225
src/main/java/org/redkale/asm/TypePath.java
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2013 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to a type argument, wildcard bound, array element type, or static
|
||||||
|
* inner type within an enclosing type.
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public class TypePath {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type path step that steps into the element type of an array type. See
|
||||||
|
* {@link #getStep getStep}.
|
||||||
|
*/
|
||||||
|
public final static int ARRAY_ELEMENT = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type path step that steps into the nested type of a class type. See
|
||||||
|
* {@link #getStep getStep}.
|
||||||
|
*/
|
||||||
|
public final static int INNER_TYPE = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type path step that steps into the bound of a wildcard type. See
|
||||||
|
* {@link #getStep getStep}.
|
||||||
|
*/
|
||||||
|
public final static int WILDCARD_BOUND = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type path step that steps into a type argument of a generic type. See
|
||||||
|
* {@link #getStep getStep}.
|
||||||
|
*/
|
||||||
|
public final static int TYPE_ARGUMENT = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The byte array where the path is stored, in Java class file format.
|
||||||
|
*/
|
||||||
|
byte[] b;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset of the first byte of the type path in 'b'.
|
||||||
|
*/
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new type path.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* the byte array containing the type path in Java class file
|
||||||
|
* format.
|
||||||
|
* @param offset
|
||||||
|
* the offset of the first byte of the type path in 'b'.
|
||||||
|
*/
|
||||||
|
TypePath(byte[] b, int offset) {
|
||||||
|
this.b = b;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the length of this path.
|
||||||
|
*
|
||||||
|
* @return the length of this path.
|
||||||
|
*/
|
||||||
|
public int getLength() {
|
||||||
|
return b[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the given step of this path.
|
||||||
|
*
|
||||||
|
* @param index
|
||||||
|
* an index between 0 and {@link #getLength()}, exclusive.
|
||||||
|
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE
|
||||||
|
* INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or
|
||||||
|
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||||
|
*/
|
||||||
|
public int getStep(int index) {
|
||||||
|
return b[offset + 2 * index + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the type argument that the given step is stepping
|
||||||
|
* into. This method should only be used for steps whose value is
|
||||||
|
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||||
|
*
|
||||||
|
* @param index
|
||||||
|
* an index between 0 and {@link #getLength()}, exclusive.
|
||||||
|
* @return the index of the type argument that the given step is stepping
|
||||||
|
* into.
|
||||||
|
*/
|
||||||
|
public int getStepArgument(int index) {
|
||||||
|
return b[offset + 2 * index + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a type path in string form, in the format used by
|
||||||
|
* {@link #toString()}, into a TypePath object.
|
||||||
|
*
|
||||||
|
* @param typePath
|
||||||
|
* a type path in string form, in the format used by
|
||||||
|
* {@link #toString()}. May be null or empty.
|
||||||
|
* @return the corresponding TypePath object, or null if the path is empty.
|
||||||
|
*/
|
||||||
|
public static TypePath fromString(final String typePath) {
|
||||||
|
if (typePath == null || typePath.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int n = typePath.length();
|
||||||
|
ByteVector out = new ByteVector(n);
|
||||||
|
out.putByte(0);
|
||||||
|
for (int i = 0; i < n;) {
|
||||||
|
char c = typePath.charAt(i++);
|
||||||
|
if (c == '[') {
|
||||||
|
out.put11(ARRAY_ELEMENT, 0);
|
||||||
|
} else if (c == '.') {
|
||||||
|
out.put11(INNER_TYPE, 0);
|
||||||
|
} else if (c == '*') {
|
||||||
|
out.put11(WILDCARD_BOUND, 0);
|
||||||
|
} else if (c >= '0' && c <= '9') {
|
||||||
|
int typeArg = c - '0';
|
||||||
|
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
|
||||||
|
typeArg = typeArg * 10 + c - '0';
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if (i < n && typePath.charAt(i) == ';') {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
out.put11(TYPE_ARGUMENT, typeArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.data[0] = (byte) (out.length / 2);
|
||||||
|
return new TypePath(out.data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT
|
||||||
|
* ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE
|
||||||
|
* INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps
|
||||||
|
* with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type
|
||||||
|
* argument index in decimal form followed by ';'.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
int length = getLength();
|
||||||
|
StringBuilder result = new StringBuilder(length * 2);
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
switch (getStep(i)) {
|
||||||
|
case ARRAY_ELEMENT:
|
||||||
|
result.append('[');
|
||||||
|
break;
|
||||||
|
case INNER_TYPE:
|
||||||
|
result.append('.');
|
||||||
|
break;
|
||||||
|
case WILDCARD_BOUND:
|
||||||
|
result.append('*');
|
||||||
|
break;
|
||||||
|
case TYPE_ARGUMENT:
|
||||||
|
result.append(getStepArgument(i)).append(';');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result.append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
481
src/main/java/org/redkale/asm/TypeReference.java
Normal file
481
src/main/java/org/redkale/asm/TypeReference.java
Normal file
@@ -0,0 +1,481 @@
|
|||||||
|
/*
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ASM: a very small and fast Java bytecode manipulation framework
|
||||||
|
* Copyright (c) 2000-2013 INRIA, France Telecom
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.redkale.asm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a type appearing in a class, field or method declaration, or
|
||||||
|
* on an instruction. Such a reference designates the part of the class where
|
||||||
|
* the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
|
||||||
|
* clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
|
||||||
|
* declaration, etc).
|
||||||
|
*
|
||||||
|
* @author Eric Bruneton
|
||||||
|
*/
|
||||||
|
public class TypeReference {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a type parameter of a generic
|
||||||
|
* class. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int CLASS_TYPE_PARAMETER = 0x00;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a type parameter of a generic
|
||||||
|
* method. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_TYPE_PARAMETER = 0x01;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the super class of a class or one
|
||||||
|
* of the interfaces it implements. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int CLASS_EXTENDS = 0x10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a bound of a type parameter of a
|
||||||
|
* generic class. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a bound of a type parameter of a
|
||||||
|
* generic method. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type of a field. See
|
||||||
|
* {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int FIELD = 0x13;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the return type of a method. See
|
||||||
|
* {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_RETURN = 0x14;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the receiver type of a method.
|
||||||
|
* See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_RECEIVER = 0x15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type of a formal parameter of
|
||||||
|
* a method. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_FORMAL_PARAMETER = 0x16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type of an exception declared
|
||||||
|
* in the throws clause of a method. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int THROWS = 0x17;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type of a local variable in a
|
||||||
|
* method. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int LOCAL_VARIABLE = 0x40;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type of a resource variable
|
||||||
|
* in a method. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int RESOURCE_VARIABLE = 0x41;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type of the exception of a
|
||||||
|
* 'catch' clause in a method. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int EXCEPTION_PARAMETER = 0x42;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type declared in an
|
||||||
|
* 'instanceof' instruction. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int INSTANCEOF = 0x43;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type of the object created by
|
||||||
|
* a 'new' instruction. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int NEW = 0x44;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the receiver type of a
|
||||||
|
* constructor reference. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int CONSTRUCTOR_REFERENCE = 0x45;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the receiver type of a method
|
||||||
|
* reference. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_REFERENCE = 0x46;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target the type declared in an explicit
|
||||||
|
* or implicit cast instruction. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int CAST = 0x47;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a type parameter of a generic
|
||||||
|
* constructor in a constructor call. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a type parameter of a generic
|
||||||
|
* method in a method call. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a type parameter of a generic
|
||||||
|
* constructor in a constructor reference. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort of type references that target a type parameter of a generic
|
||||||
|
* method in a method reference. See {@link #getSort getSort}.
|
||||||
|
*/
|
||||||
|
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type reference value in Java class file format.
|
||||||
|
*/
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new TypeReference.
|
||||||
|
*
|
||||||
|
* @param typeRef
|
||||||
|
* the int encoded value of the type reference, as received in a
|
||||||
|
* visit method related to type annotations, like
|
||||||
|
* visitTypeAnnotation.
|
||||||
|
*/
|
||||||
|
public TypeReference(int typeRef) {
|
||||||
|
this.value = typeRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a type reference of the given sort.
|
||||||
|
*
|
||||||
|
* @param sort
|
||||||
|
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
|
||||||
|
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
|
||||||
|
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
|
||||||
|
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
|
||||||
|
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
|
||||||
|
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
|
||||||
|
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
|
||||||
|
* @return a type reference of the given sort.
|
||||||
|
*/
|
||||||
|
public static TypeReference newTypeReference(int sort) {
|
||||||
|
return new TypeReference(sort << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to a type parameter of a generic class or method.
|
||||||
|
*
|
||||||
|
* @param sort
|
||||||
|
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
|
||||||
|
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
|
||||||
|
* @param paramIndex
|
||||||
|
* the type parameter index.
|
||||||
|
* @return a reference to the given generic class or method type parameter.
|
||||||
|
*/
|
||||||
|
public static TypeReference newTypeParameterReference(int sort,
|
||||||
|
int paramIndex) {
|
||||||
|
return new TypeReference((sort << 24) | (paramIndex << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to a type parameter bound of a generic class or
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @param sort
|
||||||
|
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
|
||||||
|
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
|
||||||
|
* @param paramIndex
|
||||||
|
* the type parameter index.
|
||||||
|
* @param boundIndex
|
||||||
|
* the type bound index within the above type parameters.
|
||||||
|
* @return a reference to the given generic class or method type parameter
|
||||||
|
* bound.
|
||||||
|
*/
|
||||||
|
public static TypeReference newTypeParameterBoundReference(int sort,
|
||||||
|
int paramIndex, int boundIndex) {
|
||||||
|
return new TypeReference((sort << 24) | (paramIndex << 16)
|
||||||
|
| (boundIndex << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the super class or to an interface of the
|
||||||
|
* 'implements' clause of a class.
|
||||||
|
*
|
||||||
|
* @param itfIndex
|
||||||
|
* the index of an interface in the 'implements' clause of a
|
||||||
|
* class, or -1 to reference the super class of the class.
|
||||||
|
* @return a reference to the given super type of a class.
|
||||||
|
*/
|
||||||
|
public static TypeReference newSuperTypeReference(int itfIndex) {
|
||||||
|
itfIndex &= 0xFFFF;
|
||||||
|
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the type of a formal parameter of a method.
|
||||||
|
*
|
||||||
|
* @param paramIndex
|
||||||
|
* the formal parameter index.
|
||||||
|
*
|
||||||
|
* @return a reference to the type of the given method formal parameter.
|
||||||
|
*/
|
||||||
|
public static TypeReference newFormalParameterReference(int paramIndex) {
|
||||||
|
return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
|
||||||
|
| (paramIndex << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the type of an exception, in a 'throws' clause of
|
||||||
|
* a method.
|
||||||
|
*
|
||||||
|
* @param exceptionIndex
|
||||||
|
* the index of an exception in a 'throws' clause of a method.
|
||||||
|
*
|
||||||
|
* @return a reference to the type of the given exception.
|
||||||
|
*/
|
||||||
|
public static TypeReference newExceptionReference(int exceptionIndex) {
|
||||||
|
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the type of the exception declared in a 'catch'
|
||||||
|
* clause of a method.
|
||||||
|
*
|
||||||
|
* @param tryCatchBlockIndex
|
||||||
|
* the index of a try catch block (using the order in which they
|
||||||
|
* are visited with visitTryCatchBlock).
|
||||||
|
*
|
||||||
|
* @return a reference to the type of the given exception.
|
||||||
|
*/
|
||||||
|
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
|
||||||
|
return new TypeReference((EXCEPTION_PARAMETER << 24)
|
||||||
|
| (tryCatchBlockIndex << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the type of a type argument in a constructor or
|
||||||
|
* method call or reference.
|
||||||
|
*
|
||||||
|
* @param sort
|
||||||
|
* {@link #CAST CAST},
|
||||||
|
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||||
|
* METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||||
|
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||||
|
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||||
|
* @param argIndex
|
||||||
|
* the type argument index.
|
||||||
|
*
|
||||||
|
* @return a reference to the type of the given type argument.
|
||||||
|
*/
|
||||||
|
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
|
||||||
|
return new TypeReference((sort << 24) | argIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sort of this type reference.
|
||||||
|
*
|
||||||
|
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
|
||||||
|
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
|
||||||
|
* {@link #CLASS_EXTENDS CLASS_EXTENDS},
|
||||||
|
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
|
||||||
|
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
|
||||||
|
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
|
||||||
|
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
|
||||||
|
* {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
|
||||||
|
* {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
|
||||||
|
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
|
||||||
|
* {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
|
||||||
|
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
|
||||||
|
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
|
||||||
|
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
|
||||||
|
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||||
|
* METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||||
|
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||||
|
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||||
|
*/
|
||||||
|
public int getSort() {
|
||||||
|
return value >>> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the type parameter referenced by this type
|
||||||
|
* reference. This method must only be used for type references whose sort
|
||||||
|
* is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
|
||||||
|
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
|
||||||
|
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||||
|
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
|
||||||
|
*
|
||||||
|
* @return a type parameter index.
|
||||||
|
*/
|
||||||
|
public int getTypeParameterIndex() {
|
||||||
|
return (value & 0x00FF0000) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the type parameter bound, within the type parameter
|
||||||
|
* {@link #getTypeParameterIndex}, referenced by this type reference. This
|
||||||
|
* method must only be used for type references whose sort is
|
||||||
|
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||||
|
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
|
||||||
|
*
|
||||||
|
* @return a type parameter bound index.
|
||||||
|
*/
|
||||||
|
public int getTypeParameterBoundIndex() {
|
||||||
|
return (value & 0x0000FF00) >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the "super type" of a class that is referenced by
|
||||||
|
* this type reference. This method must only be used for type references
|
||||||
|
* whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
|
||||||
|
*
|
||||||
|
* @return the index of an interface in the 'implements' clause of a class,
|
||||||
|
* or -1 if this type reference references the type of the super
|
||||||
|
* class.
|
||||||
|
*/
|
||||||
|
public int getSuperTypeIndex() {
|
||||||
|
return (short) ((value & 0x00FFFF00) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the formal parameter whose type is referenced by
|
||||||
|
* this type reference. This method must only be used for type references
|
||||||
|
* whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
|
||||||
|
*
|
||||||
|
* @return a formal parameter index.
|
||||||
|
*/
|
||||||
|
public int getFormalParameterIndex() {
|
||||||
|
return (value & 0x00FF0000) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the exception, in a 'throws' clause of a method,
|
||||||
|
* whose type is referenced by this type reference. This method must only be
|
||||||
|
* used for type references whose sort is {@link #THROWS THROWS}.
|
||||||
|
*
|
||||||
|
* @return the index of an exception in the 'throws' clause of a method.
|
||||||
|
*/
|
||||||
|
public int getExceptionIndex() {
|
||||||
|
return (value & 0x00FFFF00) >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the try catch block (using the order in which they
|
||||||
|
* are visited with visitTryCatchBlock), whose 'catch' type is referenced by
|
||||||
|
* this type reference. This method must only be used for type references
|
||||||
|
* whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
|
||||||
|
*
|
||||||
|
* @return the index of an exception in the 'throws' clause of a method.
|
||||||
|
*/
|
||||||
|
public int getTryCatchBlockIndex() {
|
||||||
|
return (value & 0x00FFFF00) >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the type argument referenced by this type reference.
|
||||||
|
* This method must only be used for type references whose sort is
|
||||||
|
* {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||||
|
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||||
|
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||||
|
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||||
|
*
|
||||||
|
* @return a type parameter index.
|
||||||
|
*/
|
||||||
|
public int getTypeArgumentIndex() {
|
||||||
|
return value & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the int encoded value of this type reference, suitable for use in
|
||||||
|
* visit methods related to type annotations, like visitTypeAnnotation.
|
||||||
|
*
|
||||||
|
* @return the int encoded value of this type reference.
|
||||||
|
*/
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/main/java/org/redkale/asm/asm.txt
Normal file
27
src/main/java/org/redkale/asm/asm.txt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
need copy classes:
|
||||||
|
|
||||||
|
AnnotationVisitor.java
|
||||||
|
AnnotationWriter.java
|
||||||
|
Attribute.java
|
||||||
|
ByteVector.java
|
||||||
|
ClassReader.java
|
||||||
|
ClassVisitor.java
|
||||||
|
ClassWriter.java
|
||||||
|
Context.java
|
||||||
|
CurrentFrame.java
|
||||||
|
Edge.java
|
||||||
|
FieldVisitor.java
|
||||||
|
FieldWriter.java
|
||||||
|
Frame.java
|
||||||
|
Handle.java
|
||||||
|
Handler.java
|
||||||
|
Item.java
|
||||||
|
Label.java
|
||||||
|
MethodVisitor.java
|
||||||
|
MethodWriter.java
|
||||||
|
ModuleVisitor.java
|
||||||
|
ModuleWriter.java
|
||||||
|
Opcodes.java
|
||||||
|
Type.java
|
||||||
|
TypePath.java
|
||||||
|
TypeReference.java
|
||||||
4
src/main/java/org/redkale/asm/package-info.java
Normal file
4
src/main/java/org/redkale/asm/package-info.java
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* 本包下所有代码均是从/java.base/jdk/internal/org/objectweb/asm 拷贝过来的
|
||||||
|
*/
|
||||||
|
package org.redkale.asm;
|
||||||
535
src/main/java/org/redkale/boot/ApiDocsService.java
Normal file
535
src/main/java/org/redkale/boot/ApiDocsService.java
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.math.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.*;
|
||||||
|
import java.util.logging.*;
|
||||||
|
import javax.persistence.*;
|
||||||
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.convert.json.*;
|
||||||
|
import org.redkale.mq.MessageMultiConsumer;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.service.RetResult;
|
||||||
|
import org.redkale.source.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API接口文档生成类,作用:生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
|
||||||
|
* 继承 HttpBaseServlet 是为了获取 HttpMapping 信息 <br>
|
||||||
|
* https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public final class ApiDocsService {
|
||||||
|
|
||||||
|
private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken<RetResult<Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken<RetResult<String>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final java.lang.reflect.Type TYPE_RETRESULT_INTEGER = new TypeToken<RetResult<Integer>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final java.lang.reflect.Type TYPE_RETRESULT_LONG = new TypeToken<RetResult<Long>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private final Application app; //Application全局对象
|
||||||
|
|
||||||
|
public ApiDocsService(Application app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(String[] args) throws Exception {
|
||||||
|
//是否跳过RPC接口
|
||||||
|
final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false");
|
||||||
|
|
||||||
|
List<Map> serverList = new ArrayList<>();
|
||||||
|
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
|
||||||
|
__prefix.setAccessible(true);
|
||||||
|
Map<String, Map<String, Map<String, Object>>> typesMap = new LinkedHashMap<>();
|
||||||
|
//https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
|
||||||
|
Map<String, Object> swaggerPathsMap = new LinkedHashMap<>();
|
||||||
|
List<Map> swaggerServers = new ArrayList<>();
|
||||||
|
List<Map> swaggerTags = new ArrayList<>();
|
||||||
|
Map<String, Map<String, Object>> swaggerComponentsMap = new LinkedHashMap<>();
|
||||||
|
for (NodeServer node : app.servers) {
|
||||||
|
if (!(node instanceof NodeHttpServer)) continue;
|
||||||
|
final Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
serverList.add(map);
|
||||||
|
HttpServer server = node.getServer();
|
||||||
|
map.put("address", server.getSocketAddress());
|
||||||
|
swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort()));
|
||||||
|
List<Map<String, Object>> servletsList = new ArrayList<>();
|
||||||
|
map.put("servlets", servletsList);
|
||||||
|
String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType;
|
||||||
|
if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json";
|
||||||
|
if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';'));
|
||||||
|
|
||||||
|
for (HttpServlet servlet : server.getPrepareServlet().getServlets()) {
|
||||||
|
if (!(servlet instanceof HttpServlet)) continue;
|
||||||
|
if (servlet instanceof WebSocketServlet) continue;
|
||||||
|
if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) {
|
||||||
|
node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
|
if (ws == null) {
|
||||||
|
node.logger.log(Level.WARNING, servlet + " not found @WebServlet");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ws.name().isEmpty()) {
|
||||||
|
node.logger.log(Level.INFO, servlet + " be skipped because @WebServlet.name is empty");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final String tag = ws.name().isEmpty() ? servlet.getClass().getSimpleName().replace("Servlet", "").toLowerCase() : ws.name();
|
||||||
|
final Map<String, Object> servletMap = new LinkedHashMap<>();
|
||||||
|
String prefix = (String) __prefix.get(servlet);
|
||||||
|
String[] urlregs = ws.value();
|
||||||
|
if (prefix != null && !prefix.isEmpty()) {
|
||||||
|
for (int i = 0; i < urlregs.length; i++) {
|
||||||
|
urlregs[i] = prefix + urlregs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
servletMap.put("urlregs", urlregs);
|
||||||
|
servletMap.put("moduleid", ws.moduleid());
|
||||||
|
servletMap.put("name", ws.name());
|
||||||
|
servletMap.put("comment", ws.comment());
|
||||||
|
|
||||||
|
List<Map> mappingsList = new ArrayList<>();
|
||||||
|
servletMap.put("mappings", mappingsList);
|
||||||
|
final Class selfClz = servlet.getClass();
|
||||||
|
Class clz = servlet.getClass();
|
||||||
|
HashSet<String> actionUrls = new HashSet<>();
|
||||||
|
do {
|
||||||
|
if (Modifier.isAbstract(clz.getModifiers())) break;
|
||||||
|
for (Method method : clz.getMethods()) {
|
||||||
|
if (method.getParameterCount() != 2) continue;
|
||||||
|
HttpMapping action = method.getAnnotation(HttpMapping.class);
|
||||||
|
if (action == null) continue;
|
||||||
|
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
|
||||||
|
if (actionUrls.contains(action.url())) continue;
|
||||||
|
if (HttpScope.class.isAssignableFrom(action.result())) continue; //忽略模板引擎的方法
|
||||||
|
if (action.rpconly() && skipRPC) continue; //不生成RPC接口
|
||||||
|
|
||||||
|
final List<Map<String, Object>> swaggerParamsList = new ArrayList<>();
|
||||||
|
|
||||||
|
final Map<String, Object> mappingMap = new LinkedHashMap<>();
|
||||||
|
mappingMap.put("url", prefix + action.url());
|
||||||
|
actionUrls.add(action.url());
|
||||||
|
mappingMap.put("auth", action.auth());
|
||||||
|
mappingMap.put("actionid", action.actionid());
|
||||||
|
mappingMap.put("comment", action.comment());
|
||||||
|
List<Map> paramsList = new ArrayList<>();
|
||||||
|
mappingMap.put("params", paramsList);
|
||||||
|
List<String> results = new ArrayList<>();
|
||||||
|
Type resultType = action.result();
|
||||||
|
if (!action.resultref().isEmpty()) {
|
||||||
|
Field f = servlet.getClass().getDeclaredField(action.resultref());
|
||||||
|
f.setAccessible(true);
|
||||||
|
resultType = (Type) f.get(servlet);
|
||||||
|
}
|
||||||
|
// for (final Class rtype : action.results()) {
|
||||||
|
// results.add(rtype.getName());
|
||||||
|
// if (typesMap.containsKey(rtype.getName())) continue;
|
||||||
|
// if (rtype.getName().startsWith("java.")) continue;
|
||||||
|
// if (rtype.getName().startsWith("javax.")) continue;
|
||||||
|
// final boolean filter = FilterBean.class.isAssignableFrom(rtype);
|
||||||
|
// final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>();
|
||||||
|
// Class loop = rtype;
|
||||||
|
// do {
|
||||||
|
// if (loop == null || loop.isInterface()) break;
|
||||||
|
// for (Field field : loop.getDeclaredFields()) {
|
||||||
|
// if (Modifier.isFinal(field.getModifiers())) continue;
|
||||||
|
// if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
|
//
|
||||||
|
// Map<String, Object> fieldmap = new LinkedHashMap<>();
|
||||||
|
// fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
|
||||||
|
//
|
||||||
|
// Comment comment = field.getAnnotation(Comment.class);
|
||||||
|
// Column col = field.getAnnotation(Column.class);
|
||||||
|
// FilterColumn fc = field.getAnnotation(FilterColumn.class);
|
||||||
|
// if (comment != null) {
|
||||||
|
// fieldmap.put("comment", comment.value());
|
||||||
|
// } else if (col != null) {
|
||||||
|
// fieldmap.put("comment", col.comment());
|
||||||
|
// } else if (fc != null) {
|
||||||
|
// fieldmap.put("comment", fc.comment());
|
||||||
|
// }
|
||||||
|
// fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
|
||||||
|
// fieldmap.put("updatable", (filter || col == null || col.updatable()));
|
||||||
|
// if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
|
||||||
|
// if (field.getAnnotation(RestAddress.class) != null) continue;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// typeMap.put(field.getName(), fieldmap);
|
||||||
|
// }
|
||||||
|
// } while ((loop = loop.getSuperclass()) != Object.class);
|
||||||
|
// typesMap.put(rtype.getName(), typeMap);
|
||||||
|
// }
|
||||||
|
mappingMap.put("results", results);
|
||||||
|
boolean hasbodyparam = false;
|
||||||
|
Map<String, Object> swaggerRequestBody = new LinkedHashMap<>();
|
||||||
|
for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
|
||||||
|
final Map<String, Object> oldapisParamMap = new LinkedHashMap<>();
|
||||||
|
final boolean isarray = param.type().isArray();
|
||||||
|
final Class ptype = isarray ? param.type().getComponentType() : param.type();
|
||||||
|
oldapisParamMap.put("name", param.name());
|
||||||
|
oldapisParamMap.put("radix", param.radix());
|
||||||
|
oldapisParamMap.put("type", ptype.getName() + (isarray ? "[]" : ""));
|
||||||
|
oldapisParamMap.put("style", param.style());
|
||||||
|
oldapisParamMap.put("comment", param.comment());
|
||||||
|
oldapisParamMap.put("required", param.required());
|
||||||
|
paramsList.add(oldapisParamMap);
|
||||||
|
{
|
||||||
|
final Map<String, Object> paramSchemaMap = new LinkedHashMap<>();
|
||||||
|
Type paramGenericType = param.type();
|
||||||
|
if (!param.typeref().isEmpty()) {
|
||||||
|
Field f = servlet.getClass().getDeclaredField(param.typeref());
|
||||||
|
f.setAccessible(true);
|
||||||
|
paramGenericType = (Type) f.get(servlet);
|
||||||
|
}
|
||||||
|
simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true);
|
||||||
|
if (param.style() == HttpParam.HttpParameterStyle.BODY) {
|
||||||
|
swaggerRequestBody.put("description", param.comment());
|
||||||
|
swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap)));
|
||||||
|
} else {
|
||||||
|
final Map<String, Object> swaggerParamMap = new LinkedHashMap<>();
|
||||||
|
swaggerParamMap.put("name", param.name());
|
||||||
|
swaggerParamMap.put("in", param.style().name().toLowerCase());
|
||||||
|
swaggerParamMap.put("description", param.comment());
|
||||||
|
swaggerParamMap.put("required", param.required());
|
||||||
|
if (param.deprecated()) {
|
||||||
|
swaggerParamMap.put("deprecated", param.deprecated());
|
||||||
|
}
|
||||||
|
//https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameterStyle
|
||||||
|
swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form");
|
||||||
|
swaggerParamMap.put("explode", true);
|
||||||
|
swaggerParamMap.put("schema", paramSchemaMap);
|
||||||
|
Object example = formatExample(param.example(), param.type(), paramGenericType);
|
||||||
|
if (example != null) swaggerParamMap.put("example", example);
|
||||||
|
if (!param.example().isEmpty()) {
|
||||||
|
swaggerParamMap.put("example", param.example());
|
||||||
|
}
|
||||||
|
swaggerParamsList.add(swaggerParamMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (param.style() == HttpParam.HttpParameterStyle.BODY) hasbodyparam = true;
|
||||||
|
if (ptype.isPrimitive() || ptype == String.class) continue;
|
||||||
|
if (typesMap.containsKey(ptype.getName())) continue;
|
||||||
|
if (ptype.getName().startsWith("java.")) continue;
|
||||||
|
if (ptype.getName().startsWith("javax.")) continue;
|
||||||
|
|
||||||
|
final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>();
|
||||||
|
Class loop = ptype;
|
||||||
|
final boolean filter = FilterBean.class.isAssignableFrom(loop);
|
||||||
|
do {
|
||||||
|
if (loop == null || loop.isInterface()) break;
|
||||||
|
for (Field field : loop.getDeclaredFields()) {
|
||||||
|
if (Modifier.isFinal(field.getModifiers())) continue;
|
||||||
|
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||||
|
|
||||||
|
Map<String, Object> fieldmap = new LinkedHashMap<>();
|
||||||
|
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
|
||||||
|
|
||||||
|
Column col = field.getAnnotation(Column.class);
|
||||||
|
FilterColumn fc = field.getAnnotation(FilterColumn.class);
|
||||||
|
Comment comment = field.getAnnotation(Comment.class);
|
||||||
|
if (comment != null) {
|
||||||
|
fieldmap.put("comment", comment.value());
|
||||||
|
} else if (col != null) {
|
||||||
|
fieldmap.put("comment", col.comment());
|
||||||
|
} else if (fc != null) {
|
||||||
|
fieldmap.put("comment", fc.comment());
|
||||||
|
}
|
||||||
|
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
|
||||||
|
fieldmap.put("updatable", (filter || col == null || col.updatable()));
|
||||||
|
|
||||||
|
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
|
||||||
|
if (field.getAnnotation(RestAddress.class) != null) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
typeMap.put(field.getName(), fieldmap);
|
||||||
|
}
|
||||||
|
} while ((loop = loop.getSuperclass()) != Object.class);
|
||||||
|
|
||||||
|
typesMap.put(ptype.getName(), typeMap);
|
||||||
|
}
|
||||||
|
mappingMap.put("result", action.result().getSimpleName().replace("void", "Object"));
|
||||||
|
mappingsList.add(mappingMap);
|
||||||
|
|
||||||
|
final Map<String, Object> swaggerOperatMap = new LinkedHashMap<>();
|
||||||
|
swaggerOperatMap.put("tags", new String[]{tag});
|
||||||
|
swaggerOperatMap.put("operationId", action.name());
|
||||||
|
if (method.getAnnotation(Deprecated.class) != null) {
|
||||||
|
swaggerOperatMap.put("deprecated", true);
|
||||||
|
}
|
||||||
|
Map<String, Object> respSchemaMap = new LinkedHashMap<>();
|
||||||
|
simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true);
|
||||||
|
|
||||||
|
Map<String, Object> respMap = new LinkedHashMap<>();
|
||||||
|
respMap.put("schema", respSchemaMap);
|
||||||
|
Object example = formatExample(action.example(), action.result(), resultType);
|
||||||
|
if (example != null) swaggerOperatMap.put("example", example);
|
||||||
|
if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody);
|
||||||
|
swaggerOperatMap.put("parameters", swaggerParamsList);
|
||||||
|
String actiondesc = action.comment();
|
||||||
|
if (action.rpconly()) actiondesc = "[Only for RPC API] " + actiondesc;
|
||||||
|
swaggerOperatMap.put("responses", Utility.ofMap("200", Utility.ofMap("description", actiondesc, "content", Utility.ofMap("application/json", respMap))));
|
||||||
|
|
||||||
|
String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase();
|
||||||
|
if (m == null) {
|
||||||
|
m = hasbodyparam || TYPE_RETRESULT_STRING.equals(resultType) || TYPE_RETRESULT_INTEGER.equals(resultType)
|
||||||
|
|| TYPE_RETRESULT_LONG.equals(resultType) || action.name().contains("create") || action.name().contains("insert")
|
||||||
|
|| action.name().contains("update") || action.name().contains("delete") || action.name().contains("send") ? "post" : "get";
|
||||||
|
}
|
||||||
|
swaggerPathsMap.put(prefix + action.url(), Utility.ofMap("description", action.comment(), m, swaggerOperatMap));
|
||||||
|
}
|
||||||
|
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
|
||||||
|
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
|
||||||
|
servletsList.add(servletMap);
|
||||||
|
if (!actionUrls.isEmpty()) swaggerTags.add(Utility.ofMap("name", tag, "description", ws.comment()));
|
||||||
|
}
|
||||||
|
servletsList.sort((o1, o2) -> {
|
||||||
|
String[] urlregs1 = (String[]) o1.get("urlregs");
|
||||||
|
String[] urlregs2 = (String[]) o2.get("urlregs");
|
||||||
|
return urlregs1.length > 0 ? (urlregs2.length > 0 ? urlregs1[0].compareTo(urlregs2[0]) : 1) : -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
{ // https://github.com/OAI/OpenAPI-Specification
|
||||||
|
Map<String, Object> swaggerResultMap = new LinkedHashMap<>();
|
||||||
|
swaggerResultMap.put("openapi", "3.0.0");
|
||||||
|
Map<String, Object> infomap = new LinkedHashMap<>();
|
||||||
|
infomap.put("title", "Redkale generate apidoc");
|
||||||
|
infomap.put("version", "1.0.0");
|
||||||
|
swaggerResultMap.put("info", infomap);
|
||||||
|
swaggerResultMap.put("servers", swaggerServers);
|
||||||
|
swaggerResultMap.put("paths", swaggerPathsMap);
|
||||||
|
swaggerResultMap.put("tags", swaggerTags);
|
||||||
|
if (!swaggerComponentsMap.isEmpty()) swaggerResultMap.put("components", Utility.ofMap("schemas", swaggerComponentsMap));
|
||||||
|
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "openapi-doc.json"));
|
||||||
|
out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8));
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Map<String, Object> oldapisResultMap = new LinkedHashMap<>();
|
||||||
|
oldapisResultMap.put("servers", serverList);
|
||||||
|
oldapisResultMap.put("types", typesMap);
|
||||||
|
final String json = JsonConvert.root().convertTo(oldapisResultMap);
|
||||||
|
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
|
||||||
|
out.write(json.getBytes(StandardCharsets.UTF_8));
|
||||||
|
out.close();
|
||||||
|
File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html");
|
||||||
|
InputStream in = null;
|
||||||
|
if (doctemplate.isFile() && doctemplate.canRead()) {
|
||||||
|
in = new FileInputStream(doctemplate);
|
||||||
|
}
|
||||||
|
if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html");
|
||||||
|
String content = Utility.read(in).replace("'${content}'", json);
|
||||||
|
in.close();
|
||||||
|
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
|
||||||
|
outhtml.write(content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
outhtml.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void simpleSchemaType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType, Map<String, Object> schemaMap, boolean recursive) {
|
||||||
|
if (type == int.class || type == Integer.class || type == AtomicInteger.class) {
|
||||||
|
schemaMap.put("type", "integer");
|
||||||
|
schemaMap.put("format", "int32");
|
||||||
|
} else if (type == long.class || type == Long.class
|
||||||
|
|| type == AtomicLong.class || type == LongAdder.class || type == BigInteger.class) {
|
||||||
|
schemaMap.put("type", "integer");
|
||||||
|
schemaMap.put("format", "int64");
|
||||||
|
} else if (type == float.class || type == Float.class) {
|
||||||
|
schemaMap.put("type", "number");
|
||||||
|
schemaMap.put("format", "float");
|
||||||
|
} else if (type == double.class || type == Double.class || type == BigDecimal.class) {
|
||||||
|
schemaMap.put("type", "number");
|
||||||
|
schemaMap.put("format", "double");
|
||||||
|
} else if (type == boolean.class || type == Boolean.class || type == AtomicBoolean.class) {
|
||||||
|
schemaMap.put("type", "boolean");
|
||||||
|
} else if (type.isPrimitive() || Number.class.isAssignableFrom(type)) {
|
||||||
|
schemaMap.put("type", "number");
|
||||||
|
} else if (type == String.class || CharSequence.class.isAssignableFrom(type)) {
|
||||||
|
schemaMap.put("type", "string");
|
||||||
|
} else if (recursive && (type.isArray() || Collection.class.isAssignableFrom(type))) {
|
||||||
|
schemaMap.put("type", "array");
|
||||||
|
Map<String, Object> sbumap = new LinkedHashMap<>();
|
||||||
|
if (type.isArray()) {
|
||||||
|
simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false);
|
||||||
|
} else if (genericType instanceof ParameterizedType) {
|
||||||
|
Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0];
|
||||||
|
if (subpt instanceof Class) {
|
||||||
|
simpleSchemaType(logger, componentsMap, (Class) subpt, subpt, sbumap, false);
|
||||||
|
} else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) {
|
||||||
|
simpleSchemaType(logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false);
|
||||||
|
} else {
|
||||||
|
sbumap.put("type", "object");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sbumap.put("type", "object");
|
||||||
|
}
|
||||||
|
schemaMap.put("items", sbumap);
|
||||||
|
} else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) {
|
||||||
|
String ct = simpleComponentType(logger, componentsMap, type, genericType);
|
||||||
|
if (ct == null) {
|
||||||
|
schemaMap.put("type", "object");
|
||||||
|
} else {
|
||||||
|
schemaMap.put("$ref", "#/components/schemas/" + ct);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
schemaMap.put("type", "object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String simpleComponentType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType) {
|
||||||
|
try {
|
||||||
|
Encodeable encodeable = JsonFactory.root().loadEncoder(genericType);
|
||||||
|
String ct = componentKey(logger, componentsMap, null, encodeable, true);
|
||||||
|
if (ct == null || ct.length() == 0) return null;
|
||||||
|
if (componentsMap.containsKey(ct)) return ct;
|
||||||
|
Map<String, Object> cmap = new LinkedHashMap<>();
|
||||||
|
componentsMap.put(ct, cmap); //必须在调用simpleSchemaType之前put,不然嵌套情况下死循环
|
||||||
|
|
||||||
|
cmap.put("type", "object");
|
||||||
|
List<String> requireds = new ArrayList<>();
|
||||||
|
Map<String, Object> properties = new LinkedHashMap<>();
|
||||||
|
if (encodeable instanceof ObjectEncoder) {
|
||||||
|
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
|
||||||
|
Map<String, Object> schemaMap = new LinkedHashMap<>();
|
||||||
|
simpleSchemaType(logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true);
|
||||||
|
String desc = "";
|
||||||
|
if (member.getField() != null) {
|
||||||
|
Column col = member.getField().getAnnotation(Column.class);
|
||||||
|
if (col == null) {
|
||||||
|
FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class);
|
||||||
|
if (fcol != null) {
|
||||||
|
desc = fcol.comment();
|
||||||
|
if (fcol.required()) requireds.add(member.getAttribute().field());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
desc = col.comment();
|
||||||
|
if (!col.nullable()) requireds.add(member.getAttribute().field());
|
||||||
|
}
|
||||||
|
if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) {
|
||||||
|
desc = member.getField().getAnnotation(Comment.class).value();
|
||||||
|
}
|
||||||
|
} else if (member.getMethod() != null) {
|
||||||
|
Column col = member.getMethod().getAnnotation(Column.class);
|
||||||
|
if (col == null) {
|
||||||
|
FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class);
|
||||||
|
if (fcol != null) {
|
||||||
|
desc = fcol.comment();
|
||||||
|
if (fcol.required()) requireds.add(member.getAttribute().field());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
desc = col.comment();
|
||||||
|
if (!col.nullable()) requireds.add(member.getAttribute().field());
|
||||||
|
}
|
||||||
|
if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) {
|
||||||
|
desc = member.getMethod().getAnnotation(Comment.class).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!desc.isEmpty()) schemaMap.put("description", desc);
|
||||||
|
properties.put(member.getAttribute().field(), schemaMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!requireds.isEmpty()) cmap.put("required", requireds);
|
||||||
|
cmap.put("properties", properties);
|
||||||
|
return ct;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, genericType + " generate component info error", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String componentKey(Logger logger, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) {
|
||||||
|
if (encodeable instanceof ObjectEncoder) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName());
|
||||||
|
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
|
||||||
|
if (member.getEncoder() instanceof ArrayEncoder
|
||||||
|
|| member.getEncoder() instanceof CollectionEncoder) {
|
||||||
|
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
|
||||||
|
if (subsb == null) return null;
|
||||||
|
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
|
||||||
|
if (real == null) continue;
|
||||||
|
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
|
||||||
|
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
|
||||||
|
if (cz == ct) continue;
|
||||||
|
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
|
||||||
|
sb.append(subsb);
|
||||||
|
} else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) {
|
||||||
|
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
|
||||||
|
if (real == null) continue;
|
||||||
|
if (member.getEncoder() instanceof SimpledCoder) {
|
||||||
|
simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
|
||||||
|
} else {
|
||||||
|
simpleSchemaType(logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
|
||||||
|
}
|
||||||
|
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
|
||||||
|
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
|
||||||
|
if (cz == ct) continue;
|
||||||
|
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
|
||||||
|
if (subsb == null) return null;
|
||||||
|
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
|
||||||
|
sb.append(subsb);
|
||||||
|
} else if (member.getEncoder() instanceof MapEncoder) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
} else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) {
|
||||||
|
final boolean array = (encodeable instanceof ArrayEncoder);
|
||||||
|
Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder();
|
||||||
|
if (subEncodeable instanceof SimpledCoder && field != null) return "";
|
||||||
|
final String sb = componentKey(logger, componentsMap, null, subEncodeable, false);
|
||||||
|
if (sb == null || sb.isEmpty()) return sb;
|
||||||
|
if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) {
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
return sb + (array ? "_Array" : "_Collection");
|
||||||
|
} else if (encodeable instanceof SimpledCoder) {
|
||||||
|
Class stype = ((SimpledCoder) encodeable).getType();
|
||||||
|
if (stype.isPrimitive() || stype == Boolean.class || Number.class.isAssignableFrom(stype) || CharSequence.class.isAssignableFrom(stype)) {
|
||||||
|
return stype.getSimpleName();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
} else if (encodeable instanceof MapEncoder) {
|
||||||
|
return first ? null : "";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object formatExample(String example, Class type, Type genericType) {
|
||||||
|
if (example == null || example.isEmpty()) return null;
|
||||||
|
if (type == Flipper.class) {
|
||||||
|
return new Flipper();
|
||||||
|
} else if (TYPE_RETRESULT_OBJECT.equals(genericType)) {
|
||||||
|
return RetResult.success();
|
||||||
|
} else if (TYPE_RETRESULT_STRING.equals(genericType)) {
|
||||||
|
return RetResult.success();
|
||||||
|
} else if (TYPE_RETRESULT_INTEGER.equals(genericType)) {
|
||||||
|
return RetResult.success(0);
|
||||||
|
} else if (TYPE_RETRESULT_LONG.equals(genericType)) {
|
||||||
|
return RetResult.success(0L);
|
||||||
|
}
|
||||||
|
return example;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
1505
src/main/java/org/redkale/boot/Application.java
Normal file
1505
src/main/java/org/redkale/boot/Application.java
Normal file
File diff suppressed because it is too large
Load Diff
69
src/main/java/org/redkale/boot/ApplicationListener.java
Normal file
69
src/main/java/org/redkale/boot/ApplicationListener.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.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 在运行start后调用
|
||||||
|
*
|
||||||
|
* @param application Application
|
||||||
|
*/
|
||||||
|
default void postStart(Application application) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application 在运行Compile前调用
|
||||||
|
*
|
||||||
|
* @param application Application
|
||||||
|
*/
|
||||||
|
default void preCompile(Application application) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application 在运行Compile后调用
|
||||||
|
*
|
||||||
|
* @param application Application
|
||||||
|
*/
|
||||||
|
default void postCompile(Application application) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application 在运行shutdown前调用
|
||||||
|
*
|
||||||
|
* @param application Application
|
||||||
|
*/
|
||||||
|
default void preShutdown(Application application) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,12 @@ package org.redkale.boot;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.Modifier;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.jar.*;
|
import java.util.jar.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import java.util.regex.*;
|
import java.util.regex.*;
|
||||||
@@ -30,16 +32,20 @@ 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 finest = logger.isLoggable(Level.FINEST); //日志级别
|
||||||
|
|
||||||
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
|
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
|
||||||
|
|
||||||
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
||||||
|
|
||||||
|
private Predicate<String> expectPredicate;
|
||||||
|
|
||||||
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
||||||
|
|
||||||
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
||||||
|
|
||||||
|
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 +62,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(RedkaleClassLoader 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(RedkaleClassLoader 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(RedkaleClassLoader classLoader, Class[] excludeSuperClasses, String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
|
||||||
ClassFilter filter = new ClassFilter(null, null);
|
ClassFilter filter = new ClassFilter(classLoader, 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 +103,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 +116,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 +130,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +140,11 @@ public final class ClassFilter<T> {
|
|||||||
*
|
*
|
||||||
* @param property AnyValue
|
* @param property AnyValue
|
||||||
* @param clazzname String
|
* @param clazzname String
|
||||||
|
* @param url URL
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final void filter(AnyValue property, String clazzname) {
|
public final void filter(AnyValue property, String clazzname, URL url) {
|
||||||
filter(property, clazzname, true);
|
filter(property, clazzname, true, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,6 +155,18 @@ public final class ClassFilter<T> {
|
|||||||
* @param autoscan 为true表示自动扫描的, false表示显著调用filter, AutoLoad的注解将被忽略
|
* @param autoscan 为true表示自动扫描的, false表示显著调用filter, AutoLoad的注解将被忽略
|
||||||
*/
|
*/
|
||||||
public final void filter(AnyValue property, String clazzname, boolean autoscan) {
|
public final void filter(AnyValue property, String clazzname, boolean autoscan) {
|
||||||
|
filter(property, clazzname, autoscan, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤指定的class
|
||||||
|
*
|
||||||
|
* @param property application.xml中对应class节点下的property属性项
|
||||||
|
* @param clazzname class名称
|
||||||
|
* @param autoscan 为true表示自动扫描的, false表示显著调用filter, AutoLoad的注解将被忽略
|
||||||
|
* @param url URL
|
||||||
|
*/
|
||||||
|
public final void filter(AnyValue property, String clazzname, boolean autoscan, URL url) {
|
||||||
boolean r = accept0(property, clazzname);
|
boolean r = accept0(property, clazzname);
|
||||||
ClassFilter cf = r ? this : null;
|
ClassFilter cf = r ? this : null;
|
||||||
if (r && ands != null) {
|
if (r && ands != null) {
|
||||||
@@ -145,39 +176,43 @@ public final class ClassFilter<T> {
|
|||||||
}
|
}
|
||||||
if (!r && ors != null) {
|
if (!r && ors != null) {
|
||||||
for (ClassFilter filter : ors) {
|
for (ClassFilter filter : ors) {
|
||||||
if (filter.accept(property, clazzname)) {
|
if (filter.accept(filter.conf, clazzname)) {
|
||||||
cf = filter;
|
cf = filter;
|
||||||
|
property = cf.conf;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cf == null || clazzname.startsWith("sun.")) return;
|
if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) 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) {
|
||||||
property = cf.conf;
|
property = cf.conf;
|
||||||
} else if (property instanceof DefaultAnyValue) {
|
} else if (property instanceof DefaultAnyValue) {
|
||||||
((DefaultAnyValue) property).addAll(cf.conf);
|
((DefaultAnyValue) property).addAllStringSet(cf.conf);
|
||||||
} else {
|
} else {
|
||||||
DefaultAnyValue dav = new DefaultAnyValue();
|
DefaultAnyValue dav = new DefaultAnyValue();
|
||||||
dav.addAll(property);
|
dav.addAllStringSet(property);
|
||||||
dav.addAll(cf.conf);
|
dav.addAllStringSet(cf.conf);
|
||||||
property = dav;
|
property = dav;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
|
||||||
if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)的
|
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)的
|
||||||
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
|
||||||
} else {
|
} else {
|
||||||
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
entrys.add(new FilterEntry(clazz, autoscan, false, property));
|
||||||
}
|
}
|
||||||
} catch (Throwable cfe) {
|
} catch (Throwable cfe) {
|
||||||
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
||||||
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) {
|
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
|
||||||
//logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe);
|
&& !clazzname.startsWith("com.mysql.") && !clazzname.startsWith("com.microsoft.") && !clazzname.startsWith("freemarker.")
|
||||||
|
&& !clazzname.startsWith("org.redkale") && (clazzname.contains("Service") || clazzname.contains("Servlet"))) {
|
||||||
|
//&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) {
|
||||||
|
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +245,7 @@ public final class ClassFilter<T> {
|
|||||||
}
|
}
|
||||||
if (!r && ors != null) {
|
if (!r && ors != null) {
|
||||||
for (ClassFilter filter : ors) {
|
for (ClassFilter filter : ors) {
|
||||||
if (filter.accept(property, classname)) return true;
|
if (filter.accept(filter.conf, classname)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
@@ -247,7 +282,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 +310,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 +346,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;
|
||||||
}
|
}
|
||||||
@@ -305,6 +354,14 @@ public final class ClassFilter<T> {
|
|||||||
this.refused = refused;
|
this.refused = refused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Predicate<String> getExpectPredicate() {
|
||||||
|
return expectPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectPredicate(Predicate<String> predicate) {
|
||||||
|
this.expectPredicate = predicate;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getPrivilegeIncludes() {
|
public Set<String> getPrivilegeIncludes() {
|
||||||
return privilegeIncludes;
|
return privilegeIncludes;
|
||||||
}
|
}
|
||||||
@@ -319,6 +376,7 @@ public final class ClassFilter<T> {
|
|||||||
|
|
||||||
public void setPrivilegeExcludes(Set<String> privilegeExcludes) {
|
public void setPrivilegeExcludes(Set<String> privilegeExcludes) {
|
||||||
this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes;
|
this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,7 +409,7 @@ public final class ClassFilter<T> {
|
|||||||
str = str.trim();
|
str = str.trim();
|
||||||
if (str.endsWith(";")) str = str.substring(0, str.length() - 1);
|
if (str.endsWith(";")) str = str.substring(0, str.length() - 1);
|
||||||
}
|
}
|
||||||
if (str != null) groups.addAll(Arrays.asList(str.split(";")));
|
if (str != null) this.groups.addAll(Arrays.asList(str.split(";")));
|
||||||
this.property = property;
|
this.property = property;
|
||||||
this.autoload = autoload;
|
this.autoload = autoload;
|
||||||
this.expect = expect;
|
this.expect = expect;
|
||||||
@@ -361,7 +419,7 @@ public final class ClassFilter<T> {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName()
|
return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName()
|
||||||
+ ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + groups + "]";
|
+ ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + this.groups + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -388,6 +446,10 @@ public final class ClassFilter<T> {
|
|||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean containsGroup(String group) {
|
||||||
|
return groups != null && groups.contains(group);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEmptyGroups() {
|
public boolean isEmptyGroups() {
|
||||||
return groups == null || groups.isEmpty();
|
return groups == null || groups.isEmpty();
|
||||||
}
|
}
|
||||||
@@ -422,24 +484,24 @@ public final class ClassFilter<T> {
|
|||||||
* 加载当前线程的classpath扫描所有class进行过滤
|
* 加载当前线程的classpath扫描所有class进行过滤
|
||||||
*
|
*
|
||||||
* @param excludeFile 不需要扫描的文件夹, 可以为null
|
* @param excludeFile 不需要扫描的文件夹, 可以为null
|
||||||
|
* @param loader RedkaleClassloader, 不可为null
|
||||||
* @param excludeRegs 包含此关键字的文件将被跳过, 可以为null
|
* @param excludeRegs 包含此关键字的文件将被跳过, 可以为null
|
||||||
* @param filters 过滤器
|
* @param filters 过滤器
|
||||||
*
|
*
|
||||||
* @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, RedkaleClassLoader loader, final String[] excludeRegs, final ClassFilter... filters) throws IOException {
|
||||||
URLClassLoader loader = (URLClassLoader) 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 && url != RedkaleClassLoader.URL_NONE) {
|
||||||
boolean skip = false;
|
boolean skip = false;
|
||||||
for (Pattern p : excludePatterns) {
|
for (Pattern p : excludePatterns) {
|
||||||
if (p.matcher(url.toString()).matches()) {
|
if (p.matcher(url.toString()).matches()) {
|
||||||
skip = false;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -458,17 +520,24 @@ public final class ClassFilter<T> {
|
|||||||
Set<String> classes = cache.get(url);
|
Set<String> classes = cache.get(url);
|
||||||
if (classes == null) {
|
if (classes == null) {
|
||||||
classes = new LinkedHashSet<>();
|
classes = new LinkedHashSet<>();
|
||||||
try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), "UTF-8"))) {
|
try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8))) {
|
||||||
Enumeration<JarEntry> it = jar.entries();
|
Enumeration<JarEntry> it = jar.entries();
|
||||||
while (it.hasMoreElements()) {
|
while (it.hasMoreElements()) {
|
||||||
String entryname = it.nextElement().getName().replace('/', '.');
|
String entryname = it.nextElement().getName().replace('/', '.');
|
||||||
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.redkaledyn.")) break; //redkale动态生成的类
|
||||||
|
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) {
|
||||||
if (filter != null) filter.filter(null, classname);
|
if (filter != null) filter.filter(null, classname, url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -477,7 +546,7 @@ public final class ClassFilter<T> {
|
|||||||
} else {
|
} else {
|
||||||
for (String classname : classes) {
|
for (String classname : classes) {
|
||||||
for (final ClassFilter filter : filters) {
|
for (final ClassFilter filter : filters) {
|
||||||
if (filter != null) filter.filter(null, classname);
|
if (filter != null) filter.filter(null, classname, url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -486,6 +555,9 @@ public final class ClassFilter<T> {
|
|||||||
Set<String> classes = cache.get(url);
|
Set<String> classes = cache.get(url);
|
||||||
if (classes == null) {
|
if (classes == null) {
|
||||||
classes = new LinkedHashSet<>();
|
classes = new LinkedHashSet<>();
|
||||||
|
final Set<String> cs = classes;
|
||||||
|
if (url == RedkaleClassLoader.URL_NONE) loader.forEachCacheClass(v -> cs.add(v));
|
||||||
|
if (cs.isEmpty()) {
|
||||||
files.clear();
|
files.clear();
|
||||||
File root = new File(url.getFile());
|
File root = new File(url.getFile());
|
||||||
String rootpath = root.getPath();
|
String rootpath = root.getPath();
|
||||||
@@ -496,14 +568,21 @@ public final class ClassFilter<T> {
|
|||||||
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) {
|
||||||
if (filter != null) filter.filter(null, classname);
|
if (filter != null) filter.filter(null, classname, url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (String classname : classes) {
|
||||||
|
for (final ClassFilter filter : filters) {
|
||||||
|
if (filter != null) filter.filter(null, classname, url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cache.put(url, classes);
|
cache.put(url, classes);
|
||||||
} else {
|
} else {
|
||||||
for (String classname : classes) {
|
for (String classname : classes) {
|
||||||
for (final ClassFilter filter : filters) {
|
for (final ClassFilter filter : filters) {
|
||||||
if (filter != null) filter.filter(null, classname);
|
if (filter != null) filter.filter(null, classname, url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,7 +595,9 @@ public final class ClassFilter<T> {
|
|||||||
files.add(root);
|
files.add(root);
|
||||||
} else if (root.isDirectory()) {
|
} else if (root.isDirectory()) {
|
||||||
if (exclude != null && exclude.equals(root)) return;
|
if (exclude != null && exclude.equals(root)) return;
|
||||||
for (File f : root.listFiles()) {
|
File[] lfs = root.listFiles();
|
||||||
|
if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()");
|
||||||
|
for (File f : lfs) {
|
||||||
loadClassFiles(exclude, f, files);
|
loadClassFiles(exclude, f, files);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import static java.nio.file.StandardCopyOption.*;
|
import static java.nio.file.StandardCopyOption.*;
|
||||||
@@ -14,6 +16,7 @@ import java.util.concurrent.*;
|
|||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
import java.util.logging.Formatter;
|
import java.util.logging.Formatter;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义的日志输出类
|
* 自定义的日志输出类
|
||||||
@@ -22,12 +25,16 @@ import java.util.logging.Formatter;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class LogFileHandler extends Handler {
|
@SuppressWarnings("unchecked")
|
||||||
|
public class LoggingFileHandler extends Handler {
|
||||||
|
|
||||||
|
//public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n";
|
||||||
|
public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SNCP的日志输出Handler
|
* SNCP的日志输出Handler
|
||||||
*/
|
*/
|
||||||
public static class SncpLogFileHandler extends LogFileHandler {
|
public static class LoggingSncpFileHandler extends LoggingFileHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPrefix() {
|
public String getPrefix() {
|
||||||
@@ -37,26 +44,25 @@ public class LogFileHandler extends Handler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认的日志时间格式化类
|
* 默认的日志时间格式化类
|
||||||
|
* 与SimpleFormatter的区别在于level不使用本地化
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static class LoggingFormater extends Formatter {
|
public static class LoggingFormater extends Formatter {
|
||||||
|
|
||||||
private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String format(LogRecord record) {
|
public String format(LogRecord log) {
|
||||||
String source;
|
String source;
|
||||||
if (record.getSourceClassName() != null) {
|
if (log.getSourceClassName() != null) {
|
||||||
source = record.getSourceClassName();
|
source = log.getSourceClassName();
|
||||||
if (record.getSourceMethodName() != null) {
|
if (log.getSourceMethodName() != null) {
|
||||||
source += " " + record.getSourceMethodName();
|
source += " " + log.getSourceMethodName();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
source = record.getLoggerName();
|
source = log.getLoggerName();
|
||||||
}
|
}
|
||||||
String message = formatMessage(record);
|
String message = formatMessage(log);
|
||||||
String throwable = "";
|
String throwable = "";
|
||||||
if (record.getThrown() != null) {
|
if (log.getThrown() != null) {
|
||||||
StringWriter sw = new StringWriter();
|
StringWriter sw = new StringWriter();
|
||||||
PrintWriter pw = new PrintWriter(sw) {
|
PrintWriter pw = new PrintWriter(sw) {
|
||||||
@Override
|
@Override
|
||||||
@@ -65,22 +71,38 @@ public class LogFileHandler extends Handler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
pw.println();
|
pw.println();
|
||||||
record.getThrown().printStackTrace(pw);
|
log.getThrown().printStackTrace(pw);
|
||||||
pw.close();
|
pw.close();
|
||||||
throwable = sw.toString();
|
throwable = sw.toString();
|
||||||
}
|
}
|
||||||
return String.format(format,
|
return String.format(FORMATTER_FORMAT,
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
source,
|
source,
|
||||||
record.getLoggerName(),
|
log.getLoggerName(),
|
||||||
record.getLevel().getName(),
|
log.getLevel().getName(),
|
||||||
message,
|
message,
|
||||||
throwable);
|
throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final LinkedBlockingQueue<LogRecord> records = new LinkedBlockingQueue();
|
public static void initDebugLogConfig() {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
final PrintStream ps = new PrintStream(out);
|
||||||
|
ps.println("handlers = java.util.logging.ConsoleHandler");
|
||||||
|
ps.println(".level = FINEST");
|
||||||
|
ps.println("jdk.level = INFO");
|
||||||
|
ps.println("sun.level = INFO");
|
||||||
|
ps.println("com.sun.level = INFO");
|
||||||
|
ps.println("javax.level = INFO");
|
||||||
|
ps.println("java.util.logging.ConsoleHandler.level = FINEST");
|
||||||
|
ps.println("java.util.logging.ConsoleHandler.formatter = " + LoggingFileHandler.LoggingFormater.class.getName());
|
||||||
|
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue();
|
||||||
|
|
||||||
private String pattern;
|
private String pattern;
|
||||||
|
|
||||||
@@ -98,6 +120,8 @@ public class LogFileHandler extends Handler {
|
|||||||
|
|
||||||
private boolean append;
|
private boolean append;
|
||||||
|
|
||||||
|
private Pattern denyreg;
|
||||||
|
|
||||||
private final AtomicLong loglength = new AtomicLong();
|
private final AtomicLong loglength = new AtomicLong();
|
||||||
|
|
||||||
private final AtomicLong logunusuallength = new AtomicLong();
|
private final AtomicLong logunusuallength = new AtomicLong();
|
||||||
@@ -110,7 +134,7 @@ public class LogFileHandler extends Handler {
|
|||||||
|
|
||||||
private OutputStream logunusualstream;
|
private OutputStream logunusualstream;
|
||||||
|
|
||||||
public LogFileHandler() {
|
public LoggingFileHandler() {
|
||||||
updateTomorrow();
|
updateTomorrow();
|
||||||
configure();
|
configure();
|
||||||
open();
|
open();
|
||||||
@@ -129,7 +153,7 @@ public class LogFileHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void open() {
|
private void open() {
|
||||||
final String name = "Logging-" + getClass().getSimpleName() + "-Thread";
|
final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread";
|
||||||
new Thread() {
|
new Thread() {
|
||||||
{
|
{
|
||||||
setName(name);
|
setName(name);
|
||||||
@@ -140,9 +164,9 @@ public class LogFileHandler extends Handler {
|
|||||||
public void run() {
|
public void run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
LogRecord record = records.take();
|
LogRecord log = logqueue.take();
|
||||||
final boolean bigger = (limit > 0 && limit <= loglength.get());
|
final boolean bigger = (limit > 0 && limit <= loglength.get());
|
||||||
final boolean changeday = tomorrow <= record.getMillis();
|
final boolean changeday = tomorrow <= log.getMillis();
|
||||||
if (bigger || changeday) {
|
if (bigger || changeday) {
|
||||||
updateTomorrow();
|
updateTomorrow();
|
||||||
if (logstream != null) {
|
if (logstream != null) {
|
||||||
@@ -153,6 +177,8 @@ public class LogFileHandler extends Handler {
|
|||||||
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
||||||
}
|
}
|
||||||
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
||||||
|
} else {
|
||||||
|
if (logfile.exists() && logfile.length() < 1) logfile.delete();
|
||||||
}
|
}
|
||||||
logstream = null;
|
logstream = null;
|
||||||
}
|
}
|
||||||
@@ -165,6 +191,8 @@ public class LogFileHandler extends Handler {
|
|||||||
if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
||||||
}
|
}
|
||||||
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
|
||||||
|
} else {
|
||||||
|
if (logunusualfile.exists() && logunusualfile.length() < 1) logunusualfile.delete();
|
||||||
}
|
}
|
||||||
logunusualstream = null;
|
logunusualstream = null;
|
||||||
}
|
}
|
||||||
@@ -185,12 +213,12 @@ public class LogFileHandler extends Handler {
|
|||||||
logunusualstream = new FileOutputStream(logunusualfile, append);
|
logunusualstream = new FileOutputStream(logunusualfile, append);
|
||||||
}
|
}
|
||||||
//----------------------写日志-------------------------
|
//----------------------写日志-------------------------
|
||||||
String message = getFormatter().format(record);
|
String message = getFormatter().format(log);
|
||||||
String encoding = getEncoding();
|
String encoding = getEncoding();
|
||||||
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
|
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
|
||||||
logstream.write(bytes);
|
logstream.write(bytes);
|
||||||
loglength.addAndGet(bytes.length);
|
loglength.addAndGet(bytes.length);
|
||||||
if (unusual != null && (record.getLevel() == Level.WARNING || record.getLevel() == Level.SEVERE)) {
|
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
|
||||||
logunusualstream.write(bytes);
|
logunusualstream.write(bytes);
|
||||||
logunusuallength.addAndGet(bytes.length);
|
logunusuallength.addAndGet(bytes.length);
|
||||||
}
|
}
|
||||||
@@ -210,7 +238,7 @@ public class LogFileHandler extends Handler {
|
|||||||
|
|
||||||
private void configure() {
|
private void configure() {
|
||||||
LogManager manager = LogManager.getLogManager();
|
LogManager manager = LogManager.getLogManager();
|
||||||
String cname = LogFileHandler.class.getName();
|
String cname = LoggingFileHandler.class.getName();
|
||||||
this.pattern = manager.getProperty(cname + ".pattern");
|
this.pattern = manager.getProperty(cname + ".pattern");
|
||||||
if (this.pattern == null) {
|
if (this.pattern == null) {
|
||||||
this.pattern = "logs-%m/" + getPrefix() + "log-%d.log";
|
this.pattern = "logs-%m/" + getPrefix() + "log-%d.log";
|
||||||
@@ -233,7 +261,21 @@ public class LogFileHandler extends Handler {
|
|||||||
}
|
}
|
||||||
String limitstr = manager.getProperty(cname + ".limit");
|
String limitstr = manager.getProperty(cname + ".limit");
|
||||||
try {
|
try {
|
||||||
if (limitstr != null) this.limit = Math.abs(Integer.decode(limitstr));
|
if (limitstr != null) {
|
||||||
|
limitstr = limitstr.toUpperCase();
|
||||||
|
boolean g = limitstr.indexOf('G') > 0;
|
||||||
|
boolean m = limitstr.indexOf('M') > 0;
|
||||||
|
boolean k = limitstr.indexOf('K') > 0;
|
||||||
|
int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", "")));
|
||||||
|
if (g) {
|
||||||
|
ls *= 1024 * 1024 * 1024;
|
||||||
|
} else if (m) {
|
||||||
|
ls *= 1024 * 1024;
|
||||||
|
} else if (k) {
|
||||||
|
ls *= 1024;
|
||||||
|
}
|
||||||
|
this.limit = ls;
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
String countstr = manager.getProperty(cname + ".count");
|
String countstr = manager.getProperty(cname + ".count");
|
||||||
@@ -258,7 +300,8 @@ public class LogFileHandler extends Handler {
|
|||||||
try {
|
try {
|
||||||
if (filterstr != null) {
|
if (filterstr != null) {
|
||||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
|
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
|
||||||
setFilter((Filter) clz.newInstance());
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||||
|
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
@@ -266,7 +309,8 @@ public class LogFileHandler extends Handler {
|
|||||||
try {
|
try {
|
||||||
if (formatterstr != null) {
|
if (formatterstr != null) {
|
||||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
|
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
|
||||||
setFormatter((Formatter) clz.newInstance());
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||||
|
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
@@ -277,23 +321,32 @@ public class LogFileHandler extends Handler {
|
|||||||
if (encodingstr != null) setEncoding(encodingstr);
|
if (encodingstr != null) setEncoding(encodingstr);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String denyregstr = manager.getProperty(cname + ".denyreg");
|
||||||
|
try {
|
||||||
|
if (denyregstr != null && !denyregstr.trim().isEmpty()) {
|
||||||
|
denyreg = Pattern.compile(denyregstr);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void publish(LogRecord record) {
|
public void publish(LogRecord log) {
|
||||||
final String sourceClassName = record.getSourceClassName();
|
final String sourceClassName = log.getSourceClassName();
|
||||||
if (sourceClassName == null || true) {
|
if (sourceClassName == null || true) {
|
||||||
StackTraceElement[] ses = new Throwable().getStackTrace();
|
StackTraceElement[] ses = new Throwable().getStackTrace();
|
||||||
for (int i = 2; i < ses.length; i++) {
|
for (int i = 2; i < ses.length; i++) {
|
||||||
if (ses[i].getClassName().startsWith("java.util.logging")) continue;
|
if (ses[i].getClassName().startsWith("java.util.logging")) continue;
|
||||||
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
|
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
|
||||||
record.setSourceMethodName(ses[i].getMethodName());
|
log.setSourceMethodName(ses[i].getMethodName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
|
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
|
||||||
}
|
}
|
||||||
records.offer(record);
|
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
|
||||||
|
logqueue.offer(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
446
src/main/java/org/redkale/boot/NodeHttpServer.java
Normal file
446
src/main/java/org/redkale/boot/NodeHttpServer.java
Normal file
@@ -0,0 +1,446 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.annotation.*;
|
||||||
|
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
|
||||||
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.cluster.ClusterAgent;
|
||||||
|
import org.redkale.mq.MessageAgent;
|
||||||
|
import org.redkale.net.*;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.net.sncp.Sncp;
|
||||||
|
import org.redkale.service.*;
|
||||||
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.watch.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP Server节点的配置Server
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@NodeProtocol("HTTP")
|
||||||
|
public class NodeHttpServer extends NodeServer {
|
||||||
|
|
||||||
|
protected final boolean rest; //是否加载REST服务, 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
|
||||||
|
|
||||||
|
protected final HttpServer httpServer;
|
||||||
|
|
||||||
|
public NodeHttpServer(Application application, AnyValue serconf) {
|
||||||
|
super(application, createServer(application, serconf));
|
||||||
|
this.httpServer = (HttpServer) server;
|
||||||
|
this.rest = serconf == null ? false : serconf.getAnyValue("rest") != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Server createServer(Application application, AnyValue serconf) {
|
||||||
|
return new HttpServer(application, application.getStartTime(), application.getResourceFactory().createChild());
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpServer getHttpServer() {
|
||||||
|
return httpServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress getSocketAddress() {
|
||||||
|
return httpServer == null ? null : httpServer.getSocketAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Service> createServiceClassFilter() {
|
||||||
|
return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||||
|
return createClassFilter(null, null, HttpFilter.class, new Class[]{WatchFilter.class}, null, "filters", "filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||||
|
return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter createOtherClassFilter() {
|
||||||
|
return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
super.loadService(serviceFilter, otherFilter);
|
||||||
|
initWebSocketService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
if (httpServer != null) loadHttpServlet(servletFilter, otherFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initWebSocketService() {
|
||||||
|
final NodeServer self = this;
|
||||||
|
final ResourceFactory regFactory = application.getResourceFactory();
|
||||||
|
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
|
||||||
|
try {
|
||||||
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if (!(src instanceof WebSocketServlet)) return;
|
||||||
|
ResourceFactory.ResourceLoader loader = null;
|
||||||
|
ResourceFactory sncpResFactory = null;
|
||||||
|
for (NodeServer ns : application.servers) {
|
||||||
|
if (!ns.isSNCP()) continue;
|
||||||
|
sncpResFactory = ns.resourceFactory;
|
||||||
|
loader = sncpResFactory.findLoader(WebSocketNode.class, field);
|
||||||
|
if (loader != null) break;
|
||||||
|
}
|
||||||
|
if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment);
|
||||||
|
synchronized (regFactory) {
|
||||||
|
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
|
||||||
|
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
|
||||||
|
resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class));
|
||||||
|
resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class));
|
||||||
|
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
|
||||||
|
}
|
||||||
|
if (nodeService == null) {
|
||||||
|
MessageAgent messageAgent = null;
|
||||||
|
try {
|
||||||
|
Field c = WebSocketServlet.class.getDeclaredField("messageAgent");
|
||||||
|
c.setAccessible(true);
|
||||||
|
messageAgent = (MessageAgent) c.get(src);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex);
|
||||||
|
}
|
||||||
|
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
|
||||||
|
regFactory.register(resourceName, WebSocketNode.class, nodeService);
|
||||||
|
}
|
||||||
|
resourceFactory.inject(nodeService, self);
|
||||||
|
field.set(src, nodeService);
|
||||||
|
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
|
||||||
|
}
|
||||||
|
}, WebSocketNode.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||||
|
for (FilterEntry<? extends Filter> en : list) {
|
||||||
|
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) continue;
|
||||||
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||||
|
final HttpFilter filter = clazz.getDeclaredConstructor().newInstance();
|
||||||
|
resourceFactory.inject(filter, this);
|
||||||
|
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
||||||
|
this.httpServer.addHttpFilter(filter, filterConf);
|
||||||
|
if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter, ClassFilter<? extends WebSocket> webSocketFilter) throws Exception {
|
||||||
|
RedkaleClassLoader.putReflectionPublicClasses(HttpServlet.class.getName());
|
||||||
|
RedkaleClassLoader.putReflectionPublicClasses(HttpPrepareServlet.class.getName());
|
||||||
|
RedkaleClassLoader.putReflectionDeclaredConstructors(HttpResourceServlet.class, HttpResourceServlet.class.getName());
|
||||||
|
final AnyValue servletsConf = this.serverConf.getAnyValue("servlets");
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
|
String prefix0 = servletsConf == null ? "" : servletsConf.getValue("path", "");
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
||||||
|
final String prefix = prefix0;
|
||||||
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys());
|
||||||
|
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
|
||||||
|
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
|
||||||
|
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
|
||||||
|
if (ws1 == ws2) {
|
||||||
|
Priority p1 = o1.getType().getAnnotation(Priority.class);
|
||||||
|
Priority p2 = o2.getType().getAnnotation(Priority.class);
|
||||||
|
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
return v == 0 ? o1.getType().getName().compareTo(o2.getType().getName()) : 0;
|
||||||
|
}
|
||||||
|
return ws1 ? -1 : 1;
|
||||||
|
});
|
||||||
|
final long starts = System.currentTimeMillis();
|
||||||
|
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
||||||
|
for (FilterEntry<? extends Servlet> en : list) {
|
||||||
|
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) continue;
|
||||||
|
if (clazz.getAnnotation(Rest.RestDyn.class) != null) continue; //动态生成的跳过
|
||||||
|
WebServlet ws = clazz.getAnnotation(WebServlet.class);
|
||||||
|
if (ws == null) continue;
|
||||||
|
if (ws.value().length == 0) {
|
||||||
|
logger.log(Level.INFO, "not found @WebServlet.value in " + clazz.getName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||||
|
final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance();
|
||||||
|
resourceFactory.inject(servlet, this);
|
||||||
|
final String[] mappings = ws.value();
|
||||||
|
String pref = ws.repair() ? prefix : "";
|
||||||
|
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
|
||||||
|
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
|
||||||
|
if (ss != null) {
|
||||||
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
|
mappings[i] = pref + mappings[i];
|
||||||
|
}
|
||||||
|
ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final List<AbstractMap.SimpleEntry<String, String[]>> rests = sb == null ? null : new ArrayList<>();
|
||||||
|
final List<AbstractMap.SimpleEntry<String, String[]>> webss = sb == null ? null : new ArrayList<>();
|
||||||
|
if (rest && serverConf != null) {
|
||||||
|
final List<Object> restedObjects = new ArrayList<>();
|
||||||
|
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
|
||||||
|
loadRestServlet(webSocketFilter, restConf, restedObjects, sb, rests, webss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int max = 0;
|
||||||
|
if (ss != null && sb != null) {
|
||||||
|
int maxTypeLength = 0;
|
||||||
|
int maxNameLength = 0;
|
||||||
|
if (rests != null) {
|
||||||
|
for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
|
||||||
|
int pos = en.getKey().indexOf('#');
|
||||||
|
if (pos > maxTypeLength) maxTypeLength = pos;
|
||||||
|
int len = en.getKey().length() - pos - 1;
|
||||||
|
if (len > maxNameLength) maxNameLength = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (webss != null) {
|
||||||
|
for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
|
||||||
|
int pos = en.getKey().indexOf('#');
|
||||||
|
if (pos > maxTypeLength) maxTypeLength = pos;
|
||||||
|
int len = en.getKey().length() - pos - 1;
|
||||||
|
if (len > maxNameLength) maxNameLength = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rests != null) {
|
||||||
|
for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
|
||||||
|
StringBuilder sub = new StringBuilder();
|
||||||
|
int pos = en.getKey().indexOf('#');
|
||||||
|
sub.append("RestDynServlet (type=").append(en.getKey().substring(0, pos));
|
||||||
|
for (int i = 0; i < maxTypeLength - pos; i++) {
|
||||||
|
sub.append(' ');
|
||||||
|
}
|
||||||
|
sub.append(", name='").append(en.getKey().substring(pos + 1));
|
||||||
|
for (int i = 0; i < maxNameLength - pos; i++) {
|
||||||
|
sub.append(' ');
|
||||||
|
}
|
||||||
|
sub.append("')");
|
||||||
|
ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (webss != null) {
|
||||||
|
for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
|
||||||
|
StringBuilder sub = new StringBuilder();
|
||||||
|
int pos = en.getKey().indexOf('#');
|
||||||
|
sub.append("RestWebSocket (type=").append(en.getKey().substring(0, pos));
|
||||||
|
for (int i = 0; i < maxTypeLength - pos; i++) {
|
||||||
|
sub.append(' ');
|
||||||
|
}
|
||||||
|
sub.append(", name='").append(en.getKey().substring(pos + 1));
|
||||||
|
for (int i = 0; i < maxNameLength - pos; i++) {
|
||||||
|
sub.append(' ');
|
||||||
|
}
|
||||||
|
sub.append("')");
|
||||||
|
ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||||
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
|
if (as.getKey().length() > max) max = as.getKey().length();
|
||||||
|
}
|
||||||
|
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||||
|
sb.append(localThreadName).append("Load ").append(as.getKey());
|
||||||
|
for (int i = 0; i < max - as.getKey().length(); i++) {
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
sb.append(localThreadName).append("All HttpServlets load cost ").append(System.currentTimeMillis() - starts).append(" ms").append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, final StringBuilder sb,
|
||||||
|
final List<AbstractMap.SimpleEntry<String, String[]>> rests, final List<AbstractMap.SimpleEntry<String, String[]>> webss) throws Exception {
|
||||||
|
if (!rest) return;
|
||||||
|
if (restConf == null) return; //不存在REST服务
|
||||||
|
|
||||||
|
String prefix0 = restConf.getValue("path", "");
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
|
||||||
|
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
|
||||||
|
|
||||||
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
String mqname = restConf.getValue("mq");
|
||||||
|
MessageAgent agent0 = null;
|
||||||
|
if (mqname != null) {
|
||||||
|
agent0 = application.getMessageAgent(mqname);
|
||||||
|
if (agent0 == null) throw new RuntimeException("not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")");
|
||||||
|
}
|
||||||
|
final MessageAgent messageAgent = agent0;
|
||||||
|
if (messageAgent != null) prefix0 = ""; //开启MQ时,prefix字段失效
|
||||||
|
final String prefix = prefix0;
|
||||||
|
final boolean autoload = restConf.getBoolValue("autoload", true);
|
||||||
|
{ //加载RestService
|
||||||
|
String userTypeStr = restConf.getValue("usertype");
|
||||||
|
final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr);
|
||||||
|
|
||||||
|
final Class baseServletType = this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName()));
|
||||||
|
final Set<String> includeValues = new HashSet<>();
|
||||||
|
final Set<String> excludeValues = new HashSet<>();
|
||||||
|
for (AnyValue item : restConf.getAnyValues("service")) {
|
||||||
|
if (item.getBoolValue("ignore", false)) {
|
||||||
|
excludeValues.add(item.getValue("value", ""));
|
||||||
|
} else {
|
||||||
|
includeValues.add(item.getValue("value", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final ClassFilter restFilter = ClassFilter.create(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : restConf.getValue("excludes", ""), includeValues, excludeValues);
|
||||||
|
final CountDownLatch scdl = new CountDownLatch(super.interceptorServices.size());
|
||||||
|
Stream<Service> stream = super.interceptorServices.stream();
|
||||||
|
if (!application.isCompileMode()) stream = stream.parallel(); //不能并行,否则在maven plugin运行环境下ClassLoader不对
|
||||||
|
stream.forEach((service) -> {
|
||||||
|
try {
|
||||||
|
final Class stype = Sncp.getServiceType(service);
|
||||||
|
final String name = Sncp.getResourceName(service);
|
||||||
|
RestService rs = (RestService) stype.getAnnotation(RestService.class);
|
||||||
|
if (rs == null || rs.ignore()) return;
|
||||||
|
|
||||||
|
final String stypename = stype.getName();
|
||||||
|
if (!autoload && !includeValues.contains(stypename)) return;
|
||||||
|
if (!restFilter.accept(stypename)) return;
|
||||||
|
synchronized (restedObjects) {
|
||||||
|
if (restedObjects.contains(service)) {
|
||||||
|
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
restedObjects.add(service); //避免重复创建Rest对象
|
||||||
|
}
|
||||||
|
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
|
||||||
|
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
|
||||||
|
String prefix2 = prefix;
|
||||||
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
|
if (ws != null && !ws.repair()) prefix2 = "";
|
||||||
|
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||||
|
dynServletMap.put(service, servlet);
|
||||||
|
if (messageAgent != null) messageAgent.putService(this, service, servlet);
|
||||||
|
//if (finest) logger.finest(localThreadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
|
||||||
|
if (rests != null) {
|
||||||
|
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||||
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
|
mappings[i] = prefix2 + mappings[i];
|
||||||
|
}
|
||||||
|
synchronized (rests) {
|
||||||
|
rests.add(new AbstractMap.SimpleEntry<>(Sncp.getServiceType(service).getName() + "#" + name, mappings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
scdl.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scdl.await();
|
||||||
|
}
|
||||||
|
if (webSocketFilter != null) { //加载RestWebSocket
|
||||||
|
final Set<String> includeValues = new HashSet<>();
|
||||||
|
final Set<String> excludeValues = new HashSet<>();
|
||||||
|
for (AnyValue item : restConf.getAnyValues("websocket")) {
|
||||||
|
if (item.getBoolValue("ignore", false)) {
|
||||||
|
excludeValues.add(item.getValue("value", ""));
|
||||||
|
} else {
|
||||||
|
includeValues.add(item.getValue("value", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final ClassFilter restFilter = ClassFilter.create(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : restConf.getValue("excludes", ""), includeValues, excludeValues);
|
||||||
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
|
||||||
|
List<FilterEntry<? extends WebSocket>> list = new ArrayList(webSocketFilter.getFilterEntrys());
|
||||||
|
for (FilterEntry<? extends WebSocket> en : list) {
|
||||||
|
Class<WebSocket> clazz = (Class<WebSocket>) en.getType();
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||||
|
logger.log(Level.FINE, clazz.getName() + " cannot abstract on rest websocket, so ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Modifier.isFinal(clazz.getModifiers())) {
|
||||||
|
logger.log(Level.FINE, clazz.getName() + " cannot final on rest websocket, so ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final Class<? extends WebSocket> stype = en.getType();
|
||||||
|
if (stype.getAnnotation(Rest.RestDyn.class) != null) continue;
|
||||||
|
RestWebSocket rs = stype.getAnnotation(RestWebSocket.class);
|
||||||
|
if (rs == null || rs.ignore()) continue;
|
||||||
|
|
||||||
|
final String stypename = stype.getName();
|
||||||
|
if (!autoload && !includeValues.contains(stypename)) continue;
|
||||||
|
if (!restFilter.accept(stypename)) continue;
|
||||||
|
if (restedObjects.contains(stype)) {
|
||||||
|
logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
restedObjects.add(stype); //避免重复创建Rest对象
|
||||||
|
WebSocketServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, messageAgent, prefix, en.getProperty());
|
||||||
|
if (servlet == null) continue; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
|
||||||
|
String prefix2 = prefix;
|
||||||
|
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||||
|
if (ws != null && !ws.repair()) prefix2 = "";
|
||||||
|
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||||
|
if (finest) logger.finest(localThreadName + " " + stype.getName() + " create a RestWebSocketServlet");
|
||||||
|
if (webss != null) {
|
||||||
|
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||||
|
for (int i = 0; i < mappings.length; i++) {
|
||||||
|
mappings[i] = prefix2 + mappings[i];
|
||||||
|
}
|
||||||
|
synchronized (webss) {
|
||||||
|
webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + "#" + rs.name(), mappings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (messageAgent != null) this.messageAgents.put(messageAgent.getName(), messageAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override //loadServlet执行之后调用
|
||||||
|
protected void postLoadServlets() {
|
||||||
|
final ClusterAgent cluster = application.clusterAgent;
|
||||||
|
if (!application.isCompileMode() && cluster != null) {
|
||||||
|
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
|
||||||
|
String protocol = pros.value().toUpperCase();
|
||||||
|
if (!cluster.containsProtocol(protocol)) return;
|
||||||
|
if (!cluster.containsPort(server.getSocketAddress().getPort())) return;
|
||||||
|
cluster.register(this, protocol, dynServletMap.keySet(), new HashSet<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) {
|
||||||
|
cluster.deregister(this, protocol, dynServletMap.keySet(), new HashSet<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/main/java/org/redkale/boot/NodeInterceptor.java
Normal file
38
src/main/java/org/redkale/boot/NodeInterceptor.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NodeServer的拦截类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class NodeInterceptor {
|
||||||
|
|
||||||
|
/** *
|
||||||
|
* Server.start之前调用 <br>
|
||||||
|
* NodeServer.start的部署是先执行NodeInterceptor.preStart,再执行 Server.start 方法
|
||||||
|
*
|
||||||
|
* @param server NodeServer
|
||||||
|
*/
|
||||||
|
public void preStart(NodeServer server) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server.shutdown之前调用 <br>
|
||||||
|
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown,再执行 Server.sshutdown 方法
|
||||||
|
*
|
||||||
|
* @param server NodeServer
|
||||||
|
*/
|
||||||
|
public void preShutdown(NodeServer server) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,5 +20,5 @@ import java.lang.annotation.*;
|
|||||||
@Documented
|
@Documented
|
||||||
public @interface NodeProtocol {
|
public @interface NodeProtocol {
|
||||||
|
|
||||||
String[] value();
|
String value();
|
||||||
}
|
}
|
||||||
910
src/main/java/org/redkale/boot/NodeServer.java
Normal file
910
src/main/java/org/redkale/boot/NodeServer.java
Normal file
@@ -0,0 +1,910 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import org.redkale.cluster.ClusterAgent;
|
||||||
|
import org.redkale.mq.MessageAgent;
|
||||||
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.AbstractMap.SimpleEntry;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.function.*;
|
||||||
|
import java.util.logging.*;
|
||||||
|
import javax.annotation.*;
|
||||||
|
import static org.redkale.boot.Application.*;
|
||||||
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.net.Filter;
|
||||||
|
import org.redkale.net.*;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.service.*;
|
||||||
|
import org.redkale.source.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server节点的初始化配置类
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public abstract class NodeServer {
|
||||||
|
|
||||||
|
//INFO日志的换行符
|
||||||
|
public static final String LINE_SEPARATOR = "\r\n";
|
||||||
|
|
||||||
|
//日志输出对象
|
||||||
|
protected final Logger logger;
|
||||||
|
|
||||||
|
//进程主类
|
||||||
|
protected final Application application;
|
||||||
|
|
||||||
|
//依赖注入工厂类
|
||||||
|
protected final ResourceFactory resourceFactory;
|
||||||
|
|
||||||
|
//当前Server对象
|
||||||
|
protected final Server server;
|
||||||
|
|
||||||
|
//ClassLoader
|
||||||
|
protected RedkaleClassLoader serverClassLoader;
|
||||||
|
|
||||||
|
protected final Thread serverThread;
|
||||||
|
|
||||||
|
//当前Server的SNCP协议的组
|
||||||
|
protected String sncpGroup = null;
|
||||||
|
|
||||||
|
//SNCP服务的地址, 非SNCP为null
|
||||||
|
private InetSocketAddress sncpAddress;
|
||||||
|
|
||||||
|
//加载Service时的处理函数
|
||||||
|
protected BiConsumer<MessageAgent, Service> consumer;
|
||||||
|
|
||||||
|
//server节点的配置
|
||||||
|
protected AnyValue serverConf;
|
||||||
|
|
||||||
|
protected final String threadName;
|
||||||
|
|
||||||
|
//加载server节点后的拦截器
|
||||||
|
protected NodeInterceptor interceptor;
|
||||||
|
|
||||||
|
//供interceptor使用的Service对象集合
|
||||||
|
protected final Set<Service> interceptorServices = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
//本地模式的Service对象集合
|
||||||
|
protected final Set<Service> localServices = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
//远程模式的Service对象集合
|
||||||
|
protected final Set<Service> remoteServices = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
protected final Map<Service, Servlet> dynServletMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
//MessageAgent对象集合
|
||||||
|
protected final Map<String, MessageAgent> messageAgents = new HashMap<>();
|
||||||
|
|
||||||
|
//需要远程模式Service的MessageAgent对象集合
|
||||||
|
protected final Map<String, MessageAgent> sncpRemoteAgents = new HashMap<>();
|
||||||
|
|
||||||
|
private volatile int maxTypeLength = 0;
|
||||||
|
|
||||||
|
private volatile int maxNameLength = 0;
|
||||||
|
|
||||||
|
public NodeServer(Application application, Server server) {
|
||||||
|
this.threadName = Thread.currentThread().getName();
|
||||||
|
this.application = application;
|
||||||
|
this.server = server;
|
||||||
|
this.resourceFactory = server.getResourceFactory();
|
||||||
|
this.logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
|
if (application.isCompileMode() || application.getServerClassLoader() instanceof RedkaleClassLoader.RedkaleCacheClassLoader) {
|
||||||
|
this.serverClassLoader = application.getServerClassLoader();
|
||||||
|
} else {
|
||||||
|
this.serverClassLoader = new RedkaleClassLoader(application.getServerClassLoader());
|
||||||
|
}
|
||||||
|
Thread.currentThread().setContextClassLoader(this.serverClassLoader);
|
||||||
|
this.serverThread = Thread.currentThread();
|
||||||
|
this.server.setServerClassLoader(serverClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) {
|
||||||
|
try {
|
||||||
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName(), Application.class, AnyValue.class);
|
||||||
|
return clazz.getDeclaredConstructor(Application.class, AnyValue.class).newInstance(application, serconf);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(AnyValue config) throws Exception {
|
||||||
|
this.serverConf = config == null ? AnyValue.create() : config;
|
||||||
|
if (isSNCP()) { // SNCP协议
|
||||||
|
String host = this.serverConf.getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0").replace("0.0.0.0", "");
|
||||||
|
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getAddress().getHostAddress() : host, this.serverConf.getIntValue("port"));
|
||||||
|
this.sncpGroup = application.sncpTransportFactory.findGroupName(this.sncpAddress);
|
||||||
|
//单向SNCP服务不需要对等group
|
||||||
|
//if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
|
||||||
|
}
|
||||||
|
//单点服务不会有 sncpAddress、sncpGroup
|
||||||
|
if (this.sncpAddress != null) {
|
||||||
|
this.resourceFactory.register(RESNAME_SNCP_ADDR, this.sncpAddress);
|
||||||
|
this.resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, this.sncpAddress);
|
||||||
|
this.resourceFactory.register(RESNAME_SNCP_ADDR, String.class, this.sncpAddress.getHostString() + ":" + this.sncpAddress.getPort());
|
||||||
|
}
|
||||||
|
if (this.sncpGroup != null) this.resourceFactory.register(RESNAME_SNCP_GROUP, this.sncpGroup);
|
||||||
|
{
|
||||||
|
//设置root文件夹
|
||||||
|
String webroot = this.serverConf.getValue("root", "root");
|
||||||
|
File myroot = new File(webroot);
|
||||||
|
if (!webroot.contains(":") && !webroot.startsWith("/")) {
|
||||||
|
myroot = new File(System.getProperty(Application.RESNAME_APP_HOME), webroot);
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceFactory.register(Server.RESNAME_SERVER_ROOT, String.class, myroot.getCanonicalPath());
|
||||||
|
resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile());
|
||||||
|
resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath());
|
||||||
|
|
||||||
|
//加入指定的classpath
|
||||||
|
Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", ""));
|
||||||
|
this.serverThread.setContextClassLoader(this.serverClassLoader);
|
||||||
|
}
|
||||||
|
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
|
||||||
|
server.init(this.serverConf);
|
||||||
|
//init之后才有Executor
|
||||||
|
//废弃 @since 2.3.0
|
||||||
|
// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, Executor.class, server.getWorkExecutor());
|
||||||
|
// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ExecutorService.class, server.getWorkExecutor());
|
||||||
|
// resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ThreadPoolExecutor.class, server.getWorkExecutor());
|
||||||
|
|
||||||
|
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
|
||||||
|
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
||||||
|
if (!interceptorClass.isEmpty()) {
|
||||||
|
Class clazz = serverClassLoader.loadClass(interceptorClass);
|
||||||
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||||
|
this.interceptor = (NodeInterceptor) clazz.getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
||||||
|
if (application.isSingletonMode()) { //singleton模式下只加载指定的Service
|
||||||
|
final String ssc = System.getProperty("red" + "kale.singleton.serviceclass");
|
||||||
|
final String extssc = System.getProperty("red" + "kale.singleton.extserviceclasses");
|
||||||
|
if (ssc != null) {
|
||||||
|
final List<String> sscList = new ArrayList<>();
|
||||||
|
sscList.add(ssc);
|
||||||
|
if (extssc != null && !extssc.isEmpty()) {
|
||||||
|
for (String s : extssc.split(",")) {
|
||||||
|
if (!s.isEmpty()) sscList.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serviceFilter.setExpectPredicate(c -> !sscList.contains(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClassFilter<Filter> filterFilter = createFilterClassFilter();
|
||||||
|
ClassFilter<Servlet> servletFilter = createServletClassFilter();
|
||||||
|
ClassFilter otherFilter = createOtherClassFilter();
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
ClassFilter.Loader.load(application.getHome(), serverClassLoader, ((application.excludelibs != null ? (application.excludelibs + ";") : "") + serverConf.getValue("excludelibs", "")).split(";"), serviceFilter, filterFilter, servletFilter, otherFilter);
|
||||||
|
long e = System.currentTimeMillis() - s;
|
||||||
|
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
||||||
|
loadService(serviceFilter, otherFilter); //必须在servlet之前
|
||||||
|
if (!application.isSingletonMode()) { //非singleton模式下才加载Filter、Servlet
|
||||||
|
loadFilter(filterFilter, otherFilter);
|
||||||
|
loadServlet(servletFilter, otherFilter);
|
||||||
|
postLoadServlets();
|
||||||
|
}
|
||||||
|
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception;
|
||||||
|
|
||||||
|
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception;
|
||||||
|
|
||||||
|
private void initResource() {
|
||||||
|
final NodeServer self = this;
|
||||||
|
//---------------------------------------------------------------------------------------------
|
||||||
|
final ResourceFactory appResFactory = application.getResourceFactory();
|
||||||
|
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
|
||||||
|
final AnyValue resources = application.config.getAnyValue("resources");
|
||||||
|
final String confURI = appResFactory.find(RESNAME_APP_CONF, String.class);
|
||||||
|
final Map<String, SimpleEntry<Class, AnyValue>> cacheResource = new HashMap<>();
|
||||||
|
final Map<String, SimpleEntry<Class, AnyValue>> dataResources = new HashMap<>();
|
||||||
|
if (resources != null) {
|
||||||
|
for (AnyValue sourceConf : resources.getAnyValues("source")) {
|
||||||
|
try {
|
||||||
|
String classval = sourceConf.getValue("value");
|
||||||
|
Class type = null;
|
||||||
|
if (classval == null || classval.isEmpty()) {
|
||||||
|
RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class);
|
||||||
|
List<CacheSourceProvider> providers = new ArrayList<>();
|
||||||
|
Iterator<CacheSourceProvider> it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
CacheSourceProvider s = it.next();
|
||||||
|
if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName());
|
||||||
|
if (s != null && s.acceptsConf(sourceConf)) {
|
||||||
|
providers.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(providers, (a, b) -> {
|
||||||
|
Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class);
|
||||||
|
Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class);
|
||||||
|
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
});
|
||||||
|
for (CacheSourceProvider provider : providers) {
|
||||||
|
type = provider.sourceClass();
|
||||||
|
if (type != null) break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = serverClassLoader.loadClass(classval);
|
||||||
|
}
|
||||||
|
if (type == DataSource.class) {
|
||||||
|
type = DataMemorySource.class;
|
||||||
|
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
|
||||||
|
if (itemConf.getValue("name", "").contains(DataSources.JDBC_URL)) {
|
||||||
|
type = DataJdbcSource.class;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Service.class.isAssignableFrom(type)) {
|
||||||
|
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
|
||||||
|
} else if (CacheSource.class.isAssignableFrom(type)) {
|
||||||
|
cacheResource.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
|
||||||
|
} else if (DataSource.class.isAssignableFrom(type)) {
|
||||||
|
dataResources.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
|
||||||
|
} else {
|
||||||
|
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "load application source resource error: " + sourceConf, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------- 注册 Resource --------------------------------------------------------
|
||||||
|
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
|
||||||
|
try {
|
||||||
|
Resource res = field.getAnnotation(Resource.class);
|
||||||
|
if (res == null || !res.name().startsWith("properties.")) return;
|
||||||
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
|
||||||
|
Class type = field.getType();
|
||||||
|
if (type != AnyValue.class && type != AnyValue[].class) return;
|
||||||
|
Object resource = null;
|
||||||
|
final AnyValue properties = resources == null ? null : resources.getAnyValue("properties");
|
||||||
|
if (properties != null && type == AnyValue.class) {
|
||||||
|
resource = properties.getAnyValue(res.name().substring("properties.".length()));
|
||||||
|
appResFactory.register(resourceName, AnyValue.class, resource);
|
||||||
|
} else if (properties != null && type == AnyValue[].class) {
|
||||||
|
resource = properties.getAnyValues(res.name().substring("properties.".length()));
|
||||||
|
appResFactory.register(resourceName, AnyValue[].class, resource);
|
||||||
|
}
|
||||||
|
field.set(src, resource);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "Resource inject error", e);
|
||||||
|
}
|
||||||
|
}, AnyValue.class, AnyValue[].class);
|
||||||
|
|
||||||
|
//------------------------------------- 注册 Local AutoLoad(false) Service --------------------------------------------------------
|
||||||
|
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
|
||||||
|
Class<Service> resServiceType = Service.class;
|
||||||
|
try {
|
||||||
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 AutoLoad Service
|
||||||
|
if (!Service.class.isAssignableFrom(field.getType())) return;
|
||||||
|
resServiceType = (Class) field.getType();
|
||||||
|
if (resServiceType.getAnnotation(Local.class) == null) return;
|
||||||
|
AutoLoad al = resServiceType.getAnnotation(AutoLoad.class);
|
||||||
|
if (al == null || al.value()) return;
|
||||||
|
|
||||||
|
//ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory);
|
||||||
|
SncpClient client = src instanceof Service ? Sncp.getSncpClient((Service) src) : null;
|
||||||
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
|
final Set<String> groups = new HashSet<>();
|
||||||
|
Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, null, appResFactory, appSncpTranFactory, sncpAddr, groups, null);
|
||||||
|
appResFactory.register(resourceName, resServiceType, service);
|
||||||
|
|
||||||
|
field.set(src, service);
|
||||||
|
rf.inject(service, self); // 给其可能包含@Resource的字段赋值;
|
||||||
|
if (!application.isCompileMode()) service.init(null);
|
||||||
|
logger.info("[" + Thread.currentThread().getName() + "] Load Service(@Local @AutoLoad service = " + resServiceType.getSimpleName() + ", resourceName = '" + resourceName + "')");
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + src + " error", e);
|
||||||
|
}
|
||||||
|
}, Service.class);
|
||||||
|
|
||||||
|
//------------------------------------- 注册 DataSource --------------------------------------------------------
|
||||||
|
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
|
||||||
|
try {
|
||||||
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
|
||||||
|
SimpleEntry<Class, AnyValue> resEntry = dataResources.get(resourceName);
|
||||||
|
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
|
||||||
|
DataSource source = null;
|
||||||
|
if (sourceConf != null) {
|
||||||
|
final Class sourceType = resEntry.getKey();
|
||||||
|
if (sourceType == DataJdbcSource.class) {
|
||||||
|
source = DataSources.createDataSource(resourceName, sourceConf);
|
||||||
|
} else {
|
||||||
|
boolean can = false;
|
||||||
|
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
|
||||||
|
for (Constructor cr : sourceType.getConstructors()) {
|
||||||
|
if (cr.getParameterCount() == 0) {
|
||||||
|
can = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DataSource.class.isAssignableFrom(sourceType) && can) { // 必须有空构造函数
|
||||||
|
if (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) {
|
||||||
|
source = (DataSource) sourceType.getConstructor().newInstance();
|
||||||
|
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
|
||||||
|
} else {
|
||||||
|
final Service srcService = (Service) src;
|
||||||
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
|
final Set<String> groups = new HashSet<>();
|
||||||
|
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (source == null) {
|
||||||
|
source = DataSources.createDataSource(confURI, resourceName); //从persistence.xml配置中创建
|
||||||
|
}
|
||||||
|
|
||||||
|
RedkaleClassLoader.putReflectionPublicConstructors(source.getClass(), source.getClass().getName());
|
||||||
|
application.dataSources.add(source);
|
||||||
|
ResourceType rt = source.getClass().getAnnotation(ResourceType.class);
|
||||||
|
if (rt != null && rt.value() != DataSource.class) {
|
||||||
|
appResFactory.register(resourceName, rt.value(), source);
|
||||||
|
} else if (source instanceof SearchSource) {
|
||||||
|
appResFactory.register(resourceName, SearchSource.class, source);
|
||||||
|
}
|
||||||
|
appResFactory.register(resourceName, DataSource.class, source);
|
||||||
|
|
||||||
|
field.set(src, source);
|
||||||
|
rf.inject(source, self); // 给AsyncGroup和其他@Resource的字段赋值;
|
||||||
|
//NodeServer.this.watchFactory.inject(src);
|
||||||
|
if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf);
|
||||||
|
logger.info("[" + Thread.currentThread().getName() + "] Load DataSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')");
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject to " + src + " error", e);
|
||||||
|
}
|
||||||
|
}, DataSource.class);
|
||||||
|
|
||||||
|
//------------------------------------- 注册 CacheSource --------------------------------------------------------
|
||||||
|
resourceFactory.register(new ResourceFactory.ResourceLoader() {
|
||||||
|
@Override
|
||||||
|
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
|
||||||
|
try {
|
||||||
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if (!(src instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + src);
|
||||||
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
|
||||||
|
final Service srcService = (Service) src;
|
||||||
|
SncpClient client = Sncp.getSncpClient(srcService);
|
||||||
|
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
|
||||||
|
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName);
|
||||||
|
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
|
||||||
|
if (sourceConf == null) {
|
||||||
|
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
|
||||||
|
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
|
||||||
|
}
|
||||||
|
Class sourceType0 = CacheMemorySource.class;
|
||||||
|
if (sourceConf != null) {
|
||||||
|
String classval = sourceConf.getValue("value");
|
||||||
|
if (classval == null || classval.isEmpty()) {
|
||||||
|
RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class);
|
||||||
|
List<CacheSourceProvider> providers = new ArrayList<>();
|
||||||
|
Iterator<CacheSourceProvider> it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
CacheSourceProvider s = it.next();
|
||||||
|
if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName());
|
||||||
|
if (s != null && s.acceptsConf(sourceConf)) {
|
||||||
|
providers.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(providers, (a, b) -> {
|
||||||
|
Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class);
|
||||||
|
Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class);
|
||||||
|
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
});
|
||||||
|
for (CacheSourceProvider provider : providers) {
|
||||||
|
sourceType0 = provider.sourceClass();
|
||||||
|
if (sourceType0 != null) break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sourceType0 = serverClassLoader.loadClass(classval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Class sourceType = sourceType0;
|
||||||
|
Object source = null;
|
||||||
|
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
|
||||||
|
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
|
||||||
|
source = sourceType == CacheMemorySource.class ? new CacheMemorySource(resourceName)
|
||||||
|
: (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) ? sourceType.getConstructor().newInstance()
|
||||||
|
: (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, null, Sncp.getConf(srcService));
|
||||||
|
Type genericType = field.getGenericType();
|
||||||
|
application.cacheSources.add((CacheSource) source);
|
||||||
|
appResFactory.register(resourceName, CacheSource.class, source);
|
||||||
|
if (genericType != CacheSource.class) {
|
||||||
|
appResFactory.register(resourceName, genericType, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
field.set(src, source);
|
||||||
|
rf.inject(source, self); //
|
||||||
|
if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf);
|
||||||
|
|
||||||
|
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
|
||||||
|
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
|
||||||
|
if (source != null && source.getClass().getAnnotation(Local.class) == null) { //本地模式的Service不生成SncpServlet
|
||||||
|
sncpServer.getSncpServer().addSncpServlet((Service) source);
|
||||||
|
}
|
||||||
|
//logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
|
||||||
|
}
|
||||||
|
logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')");
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "DataSource inject error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean autoNone() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, CacheSource.class);
|
||||||
|
|
||||||
|
//------------------------------------- 注册 WebSocketNode --------------------------------------------------------
|
||||||
|
resourceFactory.register(new ResourceFactory.ResourceLoader() {
|
||||||
|
@Override
|
||||||
|
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
|
||||||
|
try {
|
||||||
|
if (field.getAnnotation(Resource.class) == null) return;
|
||||||
|
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 WebSocketNode
|
||||||
|
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
|
||||||
|
if (nodeService == null) {
|
||||||
|
final HashSet<String> groups = new HashSet<>();
|
||||||
|
if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup);
|
||||||
|
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, Sncp.getMessageAgent((Service) src), application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null);
|
||||||
|
(isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService);
|
||||||
|
((WebSocketNodeService) nodeService).setName(resourceName);
|
||||||
|
}
|
||||||
|
resourceFactory.inject(nodeService, self);
|
||||||
|
MessageAgent messageAgent = Sncp.getMessageAgent((Service) src);
|
||||||
|
if (messageAgent != null && Sncp.getMessageAgent(nodeService) == null) Sncp.setMessageAgent(nodeService, messageAgent);
|
||||||
|
field.set(src, nodeService);
|
||||||
|
if (Sncp.isRemote(nodeService)) {
|
||||||
|
remoteServices.add(nodeService);
|
||||||
|
} else {
|
||||||
|
rf.inject(nodeService); //动态加载的Service也存在按需加载的注入资源
|
||||||
|
localServices.add(nodeService);
|
||||||
|
interceptorServices.add(nodeService);
|
||||||
|
if (consumer != null) consumer.accept(null, nodeService);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean autoNone() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, WebSocketNode.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
if (serviceFilter == null) return;
|
||||||
|
final long starts = System.currentTimeMillis();
|
||||||
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
|
||||||
|
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
|
||||||
|
final ResourceFactory appResourceFactory = application.getResourceFactory();
|
||||||
|
final TransportFactory appSncpTransFactory = application.getSncpTransportFactory();
|
||||||
|
for (FilterEntry<? extends Service> entry : entrys) { //service实现类
|
||||||
|
final Class<? extends Service> serviceImplClass = entry.getType();
|
||||||
|
if (Modifier.isFinal(serviceImplClass.getModifiers())) continue; //修饰final的类跳过
|
||||||
|
if (!Modifier.isPublic(serviceImplClass.getModifiers())) continue;
|
||||||
|
if (serviceImplClass.getAnnotation(SncpDyn.class) != null) continue; //动态生成的跳过
|
||||||
|
if (entry.isExpect()) {
|
||||||
|
if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
|
||||||
|
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
|
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
|
||||||
|
}
|
||||||
|
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
|
||||||
|
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
|
||||||
|
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
|
||||||
|
if (!Sncp.isRemote(oldother)) interceptorServices.add(oldother);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
|
||||||
|
if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup);
|
||||||
|
|
||||||
|
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !serviceImplClass.isInterface() && !Modifier.isAbstract(serviceImplClass.getModifiers())) //非SNCP的Server,通常是单点服务
|
||||||
|
|| groups.contains(this.sncpGroup) //本地IP含在内的
|
||||||
|
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|
||||||
|
|| serviceImplClass.getAnnotation(Local.class) != null;//本地模式
|
||||||
|
if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
|
||||||
|
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
|
||||||
|
try {
|
||||||
|
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的, 通常为BaseService
|
||||||
|
if (!serviceImplClass.getName().startsWith("org.redkale.") && !serviceImplClass.getSimpleName().contains("Base")) {
|
||||||
|
logger.log(Level.FINE, serviceImplClass + " cannot load because not found less one public non-final method");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RedkaleClassLoader.putReflectionPublicMethods(serviceImplClass.getName());
|
||||||
|
MessageAgent agent = null;
|
||||||
|
if (entry.getProperty() != null && entry.getProperty().getValue("mq") != null) {
|
||||||
|
agent = application.getMessageAgent(entry.getProperty().getValue("mq"));
|
||||||
|
if (agent != null) messageAgents.put(agent.getName(), agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Service service;
|
||||||
|
final boolean ws = src instanceof WebSocketServlet;
|
||||||
|
if (ws || localed) { //本地模式
|
||||||
|
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, agent, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
||||||
|
} else {
|
||||||
|
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, agent, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
|
||||||
|
}
|
||||||
|
if (service instanceof WebSocketNodeService) {
|
||||||
|
((WebSocketNodeService) service).setName(resourceName);
|
||||||
|
if (agent != null) Sncp.setMessageAgent(service, agent);
|
||||||
|
}
|
||||||
|
final Class restype = Sncp.getResourceType(service);
|
||||||
|
if (rf.find(resourceName, restype) == null) {
|
||||||
|
regFactory.register(resourceName, restype, service);
|
||||||
|
} else if (isSNCP() && !entry.isAutoload()) {
|
||||||
|
throw new RuntimeException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + resourceName + ", group:" + groups + ") is repeat.");
|
||||||
|
}
|
||||||
|
if (Sncp.isRemote(service)) {
|
||||||
|
remoteServices.add(service);
|
||||||
|
if (agent != null) sncpRemoteAgents.put(agent.getName(), agent);
|
||||||
|
} else {
|
||||||
|
if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
|
||||||
|
localServices.add(service);
|
||||||
|
interceptorServices.add(service);
|
||||||
|
if (consumer != null) consumer.accept(agent, service);
|
||||||
|
}
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
throw ex;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (entry.isExpect()) {
|
||||||
|
ResourceType rty = entry.getType().getAnnotation(ResourceType.class);
|
||||||
|
resourceFactory.register(resourceLoader, rty == null ? entry.getType() : rty.value());
|
||||||
|
} else {
|
||||||
|
resourceLoader.load(resourceFactory, null, entry.getName(), null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
application.servicecdl.countDown();
|
||||||
|
application.servicecdl.await();
|
||||||
|
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
|
//---------------- inject ----------------
|
||||||
|
new ArrayList<>(localServices).forEach(y -> {
|
||||||
|
resourceFactory.inject(y, NodeServer.this);
|
||||||
|
});
|
||||||
|
new ArrayList<>(remoteServices).forEach(y -> {
|
||||||
|
resourceFactory.inject(y, NodeServer.this);
|
||||||
|
calcMaxLength(y);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sb != null) {
|
||||||
|
remoteServices.forEach(y -> {
|
||||||
|
sb.append(localThreadName).append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)).append(" load and inject").append(LINE_SEPARATOR);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isSNCP() && !sncpRemoteAgents.isEmpty()) {
|
||||||
|
sncpRemoteAgents.values().forEach(agent -> {
|
||||||
|
// agent.putSncpResp((NodeSncpServer) this);
|
||||||
|
// agent.startSncpRespConsumer();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//----------------- init -----------------
|
||||||
|
List<Service> swlist = new ArrayList<>(localServices);
|
||||||
|
swlist.forEach(y -> calcMaxLength(y));
|
||||||
|
swlist.sort((o1, o2) -> {
|
||||||
|
Priority p1 = o1.getClass().getAnnotation(Priority.class);
|
||||||
|
Priority p2 = o2.getClass().getAnnotation(Priority.class);
|
||||||
|
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
|
||||||
|
if (v != 0) return v;
|
||||||
|
int rs = Sncp.getResourceType(o1).getName().compareTo(Sncp.getResourceType(o2).getName());
|
||||||
|
if (rs == 0) rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2));
|
||||||
|
return rs;
|
||||||
|
});
|
||||||
|
localServices.clear();
|
||||||
|
localServices.addAll(swlist);
|
||||||
|
//this.loadPersistData();
|
||||||
|
long preinits = System.currentTimeMillis();
|
||||||
|
preInitServices(localServices, remoteServices);
|
||||||
|
long preinite = System.currentTimeMillis() - preinits;
|
||||||
|
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
|
||||||
|
if (application.isCompileMode()) {
|
||||||
|
localServices.stream().forEach(y -> {
|
||||||
|
String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength);
|
||||||
|
if (slist != null) slist.add(new StringBuilder().append(localThreadName).append(serstr).append(" load").append(LINE_SEPARATOR).toString());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
localServices.stream().forEach(y -> {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
y.init(Sncp.getConf(y));
|
||||||
|
long e = System.currentTimeMillis() - s;
|
||||||
|
String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength);
|
||||||
|
if (slist != null) slist.add(new StringBuilder().append(localThreadName).append(serstr).append(" load and init in ").append(e < 10 ? " " : (e < 100 ? " " : "")).append(e).append(" ms").append(LINE_SEPARATOR).toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (slist != null && sb != null) {
|
||||||
|
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
|
||||||
|
for (String s : wlist) {
|
||||||
|
sb.append(s);
|
||||||
|
}
|
||||||
|
sb.append(localThreadName).append("All Services load cost ").append(System.currentTimeMillis() - starts).append(" ms" + LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
if (sb != null && preinite > 10) sb.append(localThreadName).append(ClusterAgent.class.getSimpleName()).append(" register ").append(preinite).append(" ms" + LINE_SEPARATOR);
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcMaxLength(Service y) { //计算toString中的长度
|
||||||
|
maxNameLength = Math.max(maxNameLength, Sncp.getResourceName(y).length());
|
||||||
|
maxTypeLength = Math.max(maxTypeLength, Sncp.getResourceType(y).getName().length() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Service.init执行之前调用
|
||||||
|
protected void preInitServices(Set<Service> localServices, Set<Service> remoteServices) {
|
||||||
|
final ClusterAgent cluster = application.clusterAgent;
|
||||||
|
if (!application.isCompileMode() && cluster != null) {
|
||||||
|
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
|
||||||
|
String protocol = pros.value().toUpperCase();
|
||||||
|
if (!cluster.containsProtocol(protocol)) return;
|
||||||
|
if (!cluster.containsPort(server.getSocketAddress().getPort())) return;
|
||||||
|
cluster.register(this, protocol, localServices, remoteServices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//loadServlet执行之后调用
|
||||||
|
protected void postLoadServlets() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Service.destroy执行之前调用
|
||||||
|
protected void preDestroyServices(Set<Service> localServices, Set<Service> remoteServices) {
|
||||||
|
if (!application.isCompileMode() && application.clusterAgent != null) { //服务注销
|
||||||
|
final ClusterAgent cluster = application.clusterAgent;
|
||||||
|
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
|
||||||
|
String protocol = pros.value().toUpperCase();
|
||||||
|
if (cluster.containsProtocol(protocol) && cluster.containsPort(server.getSocketAddress().getPort())) {
|
||||||
|
cluster.deregister(this, protocol, localServices, remoteServices);
|
||||||
|
afterClusterDeregisterOnPreDestroyServices(cluster, protocol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!application.isCompileMode() && !this.messageAgents.isEmpty()) { //MQ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//Server.start执行之后调用
|
||||||
|
protected void postStartServer(Set<Service> localServices, Set<Service> remoteServices) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract ClassFilter<Filter> createFilterClassFilter();
|
||||||
|
|
||||||
|
protected abstract ClassFilter<Servlet> createServletClassFilter();
|
||||||
|
|
||||||
|
protected ClassFilter createOtherClassFilter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ClassFilter<Service> createServiceClassFilter() {
|
||||||
|
return createClassFilter(this.sncpGroup, null, Service.class, (!isSNCP() && application.watching) ? null : new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref,
|
||||||
|
Class inter, Class[] excludeSuperClasses, Class<? extends Annotation> ref2, String properties, String property) {
|
||||||
|
ClassFilter cf = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, null);
|
||||||
|
if (properties == null && properties == null) {
|
||||||
|
cf.setRefused(true);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
|
if (this.serverConf == null) {
|
||||||
|
cf.setRefused(true);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
|
AnyValue[] proplist = this.serverConf.getAnyValues(properties);
|
||||||
|
if (proplist == null || proplist.length < 1) {
|
||||||
|
cf.setRefused(true);
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
|
cf = null;
|
||||||
|
for (AnyValue list : proplist) {
|
||||||
|
AnyValue.DefaultAnyValue prop = null;
|
||||||
|
String sc = list.getValue("groups");
|
||||||
|
String mq = list.getValue("mq");
|
||||||
|
if (sc != null) {
|
||||||
|
sc = sc.trim();
|
||||||
|
if (sc.endsWith(";")) sc = sc.substring(0, sc.length() - 1);
|
||||||
|
}
|
||||||
|
if (sc == null) sc = localGroup;
|
||||||
|
if (sc != null || mq != null) {
|
||||||
|
prop = new AnyValue.DefaultAnyValue();
|
||||||
|
if (sc != null) prop.addValue("groups", sc);
|
||||||
|
if (mq != null) prop.addValue("mq", mq);
|
||||||
|
}
|
||||||
|
ClassFilter filter = new ClassFilter(this.serverClassLoader, ref, inter, excludeSuperClasses, prop);
|
||||||
|
for (AnyValue av : list.getAnyValues(property)) { // <service>、<filter>、<servlet> 节点
|
||||||
|
final AnyValue[] items = av.getAnyValues("property");
|
||||||
|
if (av instanceof AnyValue.DefaultAnyValue && items.length > 0) { //存在 <property>节点
|
||||||
|
AnyValue.DefaultAnyValue dav = AnyValue.DefaultAnyValue.create();
|
||||||
|
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
|
||||||
|
if (strings != null) { //将<service>、<filter>、<servlet>节点的属性值传给dav
|
||||||
|
for (AnyValue.Entry<String> en : strings) {
|
||||||
|
dav.addValue(en.name, en.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys();
|
||||||
|
if (anys != null) {
|
||||||
|
for (AnyValue.Entry<AnyValue> en : anys) { //将<service>、<filter>、<servlet>节点的非property属性节点传给dav
|
||||||
|
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyValue.DefaultAnyValue ps = AnyValue.DefaultAnyValue.create();
|
||||||
|
for (AnyValue item : items) {
|
||||||
|
ps.addValue(item.getValue("name"), item.getValue("value"));
|
||||||
|
}
|
||||||
|
dav.addValue("properties", ps);
|
||||||
|
av = dav;
|
||||||
|
}
|
||||||
|
if (!av.getBoolValue("ignore", false)) {
|
||||||
|
filter.filter(av, av.getValue("value"), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (list.getBoolValue("autoload", true)) {
|
||||||
|
String includes = list.getValue("includes", "");
|
||||||
|
String excludes = list.getValue("excludes", "");
|
||||||
|
filter.setIncludePatterns(includes.split(";"));
|
||||||
|
filter.setExcludePatterns(excludes.split(";"));
|
||||||
|
} else if (ref2 == null || ref2 == Annotation.class) { //service如果是autoload=false则不需要加载
|
||||||
|
filter.setRefused(true);
|
||||||
|
} else if (ref2 != Annotation.class) {
|
||||||
|
filter.setAnnotationClass(ref2);
|
||||||
|
}
|
||||||
|
cf = (cf == null) ? filter : cf.or(filter);
|
||||||
|
}
|
||||||
|
return cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract InetSocketAddress getSocketAddress();
|
||||||
|
|
||||||
|
public boolean isSNCP() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWATCH() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application getApplication() {
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceFactory getResourceFactory() {
|
||||||
|
return resourceFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedkaleClassLoader getServerClassLoader() {
|
||||||
|
return serverClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerClassLoader(RedkaleClassLoader serverClassLoader) {
|
||||||
|
Objects.requireNonNull(this.serverClassLoader);
|
||||||
|
this.serverClassLoader = serverClassLoader;
|
||||||
|
this.serverThread.setContextClassLoader(serverClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress getSncpAddress() {
|
||||||
|
return sncpAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnyValue getServerConf() {
|
||||||
|
return serverConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Logger getLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSncpGroup() {
|
||||||
|
return sncpGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() throws IOException {
|
||||||
|
if (interceptor != null) interceptor.preStart(this);
|
||||||
|
server.start();
|
||||||
|
postStartServer(localServices, remoteServices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() throws IOException {
|
||||||
|
if (interceptor != null) interceptor.preShutdown(this);
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
preDestroyServices(localServices, remoteServices);
|
||||||
|
localServices.forEach(y -> {
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
if (finest) logger.finest(y + " is destroying");
|
||||||
|
y.destroy(Sncp.getConf(y));
|
||||||
|
if (finest) logger.finest(y + " was destroyed");
|
||||||
|
long e = System.currentTimeMillis() - s;
|
||||||
|
if (e > 2 && sb != null) {
|
||||||
|
sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
|
server.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void command(String cmd) throws IOException {
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||||
|
final boolean finest = logger.isLoggable(Level.FINEST);
|
||||||
|
localServices.forEach(y -> {
|
||||||
|
Set<Method> methods = new HashSet<>();
|
||||||
|
Class loop = y.getClass();
|
||||||
|
//do { public方法不用递归
|
||||||
|
for (Method m : loop.getMethods()) {
|
||||||
|
Command c = m.getAnnotation(Command.class);
|
||||||
|
if (c == null) continue;
|
||||||
|
if (Modifier.isStatic(m.getModifiers())) continue;
|
||||||
|
if (m.getReturnType() != void.class) continue;
|
||||||
|
if (m.getParameterCount() != 1) continue;
|
||||||
|
if (m.getParameterTypes()[0] != String.class) continue;
|
||||||
|
methods.add(m);
|
||||||
|
}
|
||||||
|
//} while ((loop = loop.getSuperclass()) != Object.class);
|
||||||
|
if (methods.isEmpty()) return;
|
||||||
|
long s = System.currentTimeMillis();
|
||||||
|
Method one = null;
|
||||||
|
try {
|
||||||
|
for (Method method : methods) {
|
||||||
|
one = method;
|
||||||
|
method.invoke(y, cmd);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.SEVERE, one + " run error, cmd = " + cmd, ex);
|
||||||
|
}
|
||||||
|
long e = System.currentTimeMillis() - s;
|
||||||
|
if (e > 10 && sb != null) {
|
||||||
|
sb.append(Sncp.toSimpleString(y, maxNameLength, maxTypeLength)).append(" command (").append(cmd).append(") ").append(e).append("ms").append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Server> T getServer() {
|
||||||
|
return (T) server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Service> getInterceptorServices() {
|
||||||
|
return new LinkedHashSet<>(interceptorServices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Service> getLocalServices() {
|
||||||
|
return new LinkedHashSet<>(localServices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Service> getRemoteServices() {
|
||||||
|
return new LinkedHashSet<>(remoteServices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getThreadName() {
|
||||||
|
return this.threadName;
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/main/java/org/redkale/boot/NodeSncpServer.java
Normal file
125
src/main/java/org/redkale/boot/NodeSncpServer.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.mq.MessageAgent;
|
||||||
|
import org.redkale.net.*;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.service.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SNCP Server节点的配置Server
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@NodeProtocol("SNCP")
|
||||||
|
public class NodeSncpServer extends NodeServer {
|
||||||
|
|
||||||
|
protected final SncpServer sncpServer;
|
||||||
|
|
||||||
|
private NodeSncpServer(Application application, AnyValue serconf) {
|
||||||
|
super(application, createServer(application, serconf));
|
||||||
|
this.sncpServer = (SncpServer) this.server;
|
||||||
|
this.consumer = sncpServer == null || application.isSingletonMode() ? null : (agent, x) -> {//singleton模式下不生成SncpServlet
|
||||||
|
if (x.getClass().getAnnotation(Local.class) != null) return; //本地模式的Service不生成SncpServlet
|
||||||
|
SncpDynServlet servlet = sncpServer.addSncpServlet(x);
|
||||||
|
dynServletMap.put(x, servlet);
|
||||||
|
if (agent != null) agent.putService(this, x, servlet);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
||||||
|
return new NodeSncpServer(application, serconf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Server createServer(Application application, AnyValue serconf) {
|
||||||
|
return new SncpServer(application, application.getStartTime(), serconf, application.getResourceFactory().createChild());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress getSocketAddress() {
|
||||||
|
return sncpServer == null ? null : sncpServer.getSocketAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void consumerAccept(MessageAgent messageAgent, Service service) {
|
||||||
|
if (this.consumer != null) this.consumer.accept(messageAgent, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(AnyValue config) throws Exception {
|
||||||
|
super.init(config);
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
if (sncpServer == null) return; //调试时server才可能为null
|
||||||
|
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
|
||||||
|
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
List<SncpServlet> servlets = sncpServer.getSncpServlets();
|
||||||
|
Collections.sort(servlets);
|
||||||
|
for (SncpServlet en : servlets) {
|
||||||
|
if (sb != null) sb.append(localThreadName).append(" Load ").append(en).append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSNCP() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SncpServer getSncpServer() {
|
||||||
|
return sncpServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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 localThreadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||||
|
for (FilterEntry<? extends Filter> en : list) {
|
||||||
|
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
|
||||||
|
if (Modifier.isAbstract(clazz.getModifiers())) continue;
|
||||||
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||||
|
final SncpFilter filter = clazz.getDeclaredConstructor().newInstance();
|
||||||
|
resourceFactory.inject(filter, this);
|
||||||
|
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
|
||||||
|
this.sncpServer.addSncpFilter(filter, filterConf);
|
||||||
|
if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
|
||||||
|
}
|
||||||
|
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
|
||||||
|
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
|
||||||
|
RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||||
|
return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
53
src/main/java/org/redkale/boot/NodeWatchServer.java
Normal file
53
src/main/java/org/redkale/boot/NodeWatchServer.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Service> createServiceClassFilter() {
|
||||||
|
return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||||
|
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||||
|
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClassFilter createOtherClassFilter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWATCH() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/main/java/org/redkale/boot/PrepareCompiler.java
Normal file
86
src/main/java/org/redkale/boot/PrepareCompiler.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import org.redkale.boot.ClassFilter.FilterEntry;
|
||||||
|
import org.redkale.convert.Decodeable;
|
||||||
|
import org.redkale.convert.bson.BsonFactory;
|
||||||
|
import org.redkale.convert.json.*;
|
||||||
|
import org.redkale.source.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行一次Application.run提前获取所有动态类
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class PrepareCompiler {
|
||||||
|
|
||||||
|
// public static void main(String[] args) throws Exception {
|
||||||
|
// new PrepareCompiler().run();
|
||||||
|
// }
|
||||||
|
public Application run() throws Exception {
|
||||||
|
final Application application = new Application(false, true, Application.loadAppConfig());
|
||||||
|
application.init();
|
||||||
|
for (ApplicationListener listener : application.listeners) {
|
||||||
|
listener.preStart(application);
|
||||||
|
}
|
||||||
|
for (ApplicationListener listener : application.listeners) {
|
||||||
|
listener.preCompile(application);
|
||||||
|
}
|
||||||
|
application.start();
|
||||||
|
final boolean hasSncp = application.getNodeServers().stream().filter(v -> v instanceof NodeSncpServer).findFirst().isPresent();
|
||||||
|
final String[] exlibs = (application.excludelibs != null ? (application.excludelibs + ";") : "").split(";");
|
||||||
|
|
||||||
|
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class, (Class[]) null);
|
||||||
|
final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class, (Class[]) null);
|
||||||
|
final ClassFilter<?> filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class, (Class[]) null);
|
||||||
|
|
||||||
|
ClassFilter.Loader.load(application.getHome(), application.getClassLoader(), exlibs, entityFilter, beanFilter, filterFilter);
|
||||||
|
|
||||||
|
for (FilterEntry en : entityFilter.getFilterEntrys()) {
|
||||||
|
Class clz = en.getType();
|
||||||
|
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
|
||||||
|
try {
|
||||||
|
application.dataSources.forEach(source -> source.compile(clz));
|
||||||
|
JsonFactory.root().loadEncoder(clz);
|
||||||
|
if (hasSncp) BsonFactory.root().loadEncoder(clz);
|
||||||
|
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||||
|
if (hasSncp) BsonFactory.root().loadDecoder(clz);
|
||||||
|
decoder.convertFrom(new JsonReader("{}"));
|
||||||
|
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (FilterEntry en : beanFilter.getFilterEntrys()) {
|
||||||
|
Class clz = en.getType();
|
||||||
|
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
|
||||||
|
try {
|
||||||
|
JsonFactory.root().loadEncoder(clz);
|
||||||
|
if (hasSncp) BsonFactory.root().loadEncoder(clz);
|
||||||
|
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||||
|
if (hasSncp) BsonFactory.root().loadDecoder(clz);
|
||||||
|
decoder.convertFrom(new JsonReader("{}"));
|
||||||
|
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (FilterEntry en : filterFilter.getFilterEntrys()) {
|
||||||
|
Class clz = en.getType();
|
||||||
|
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
|
||||||
|
try {
|
||||||
|
FilterNodeBean.load(clz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ApplicationListener listener : application.listeners) {
|
||||||
|
listener.postCompile(application);
|
||||||
|
}
|
||||||
|
application.shutdown();
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
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>');
|
||||||
html.push('<td class="s">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
|
html.push('<td class="s" style="width:80px;">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
|
||||||
var paramshtml = [];
|
var paramshtml = [];
|
||||||
paramshtml.push('<table class="subtable">');
|
paramshtml.push('<table class="subtable">');
|
||||||
for (var p = 0; p < action.params.length; p++) {
|
for (var p = 0; p < action.params.length; p++) {
|
||||||
@@ -55,8 +55,8 @@
|
|||||||
} else {
|
} else {
|
||||||
var w = param.required ? "font-weight:bold;" : "";
|
var w = param.required ? "font-weight:bold;" : "";
|
||||||
var c = ' style="' + w + '"';
|
var c = ' style="' + w + '"';
|
||||||
if (param.src == "HEADER") c = ' style="color:red;' + w + '"';
|
if (param.style == "HEADER") c = ' style="color:red;' + w + '"';
|
||||||
if (param.src == "COOKIE") c = ' style="color:blue;' + w + '"';
|
if (param.style == "COOKIE") c = ' style="color:blue;' + w + '"';
|
||||||
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
|
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import org.redkale.service.AbstractService;
|
||||||
|
import org.redkale.util.Comment;
|
||||||
|
import org.redkale.watch.WatchService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public abstract class AbstractWatchService extends AbstractService implements WatchService {
|
||||||
|
|
||||||
|
@Comment("缺少参数")
|
||||||
|
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
|
||||||
|
|
||||||
|
@Comment("执行异常")
|
||||||
|
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
|
||||||
|
}
|
||||||
80
src/main/java/org/redkale/boot/watch/FilterWatchService.java
Normal file
80
src/main/java/org/redkale/boot/watch/FilterWatchService.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.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
|
||||||
|
protected 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test1", auth = false, comment = "预留")
|
||||||
|
public RetResult test1() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test2", auth = false, comment = "预留")
|
||||||
|
public RetResult test2() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test3", auth = false, comment = "预留")
|
||||||
|
public RetResult test3() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test4", auth = false, comment = "预留")
|
||||||
|
public RetResult test4() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test5", auth = false, comment = "预留")
|
||||||
|
public RetResult test5() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test6", auth = false, comment = "预留")
|
||||||
|
public RetResult test6() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/main/java/org/redkale/boot/watch/ServerWatchService.java
Normal file
104
src/main/java/org/redkale/boot/watch/ServerWatchService.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.*;
|
||||||
|
import org.redkale.net.Server;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.service.RetResult;
|
||||||
|
import org.redkale.util.Comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "server", catalog = "watch", repair = false)
|
||||||
|
public class ServerWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
@Comment("不存在的Server节点")
|
||||||
|
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
|
||||||
|
|
||||||
|
@Comment("更改Server监听地址端口失败")
|
||||||
|
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected Application application;
|
||||||
|
|
||||||
|
@RestMapping(name = "info", comment = "单个Server信息查询")
|
||||||
|
public RetResult info(@RestParam(name = "#port:") final int port) {
|
||||||
|
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||||
|
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null);
|
||||||
|
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
|
||||||
|
return new RetResult(formatToMap(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "infos", comment = "Server信息查询")
|
||||||
|
public RetResult infos() {
|
||||||
|
Map<String, Object> rs = new LinkedHashMap<>();
|
||||||
|
for (NodeServer ns : application.getNodeServers()) {
|
||||||
|
Server server = ns.getServer();
|
||||||
|
rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns));
|
||||||
|
}
|
||||||
|
return new RetResult(rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
|
||||||
|
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
|
||||||
|
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
|
||||||
|
if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
|
||||||
|
if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
|
||||||
|
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||||
|
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null);
|
||||||
|
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
|
||||||
|
final Server server = node.getServer();
|
||||||
|
InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
|
||||||
|
try {
|
||||||
|
server.changeAddress(application, newAddr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error");
|
||||||
|
}
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> formatToMap(NodeServer node) {
|
||||||
|
Server server = node.getServer();
|
||||||
|
Map<String, Object> rs = new LinkedHashMap<>();
|
||||||
|
String protocol = server.getNetprotocol();
|
||||||
|
if (node instanceof NodeSncpServer) {
|
||||||
|
protocol += "/SNCP";
|
||||||
|
} else if (node instanceof NodeWatchServer) {
|
||||||
|
protocol += "/WATCH";
|
||||||
|
} else if (node instanceof NodeHttpServer) {
|
||||||
|
protocol += "/HTTP";
|
||||||
|
} else {
|
||||||
|
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
|
||||||
|
protocol += "/" + np.value();
|
||||||
|
}
|
||||||
|
rs.put("name", server.getName());
|
||||||
|
rs.put("protocol", protocol);
|
||||||
|
rs.put("address", server.getSocketAddress());
|
||||||
|
rs.put("backlog", server.getBacklog());
|
||||||
|
rs.put("bufferCapacity", server.getBufferCapacity());
|
||||||
|
rs.put("bufferPoolSize", server.getBufferPoolSize());
|
||||||
|
rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name());
|
||||||
|
rs.put("maxbody", server.getMaxbody());
|
||||||
|
rs.put("maxconns", server.getMaxconns());
|
||||||
|
rs.put("serverStartTime", server.getServerStartTime());
|
||||||
|
rs.put("responsePoolSize", server.getResponsePoolSize());
|
||||||
|
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());
|
||||||
|
rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds());
|
||||||
|
rs.put("createConnectionCount", server.getCreateConnectionCount());
|
||||||
|
rs.put("livingConnectionCount", server.getLivingConnectionCount());
|
||||||
|
rs.put("closedConnectionCount", server.getClosedConnectionCount());
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
}
|
||||||
199
src/main/java/org/redkale/boot/watch/ServiceWatchService.java
Normal file
199
src/main/java/org/redkale/boot/watch/ServiceWatchService.java
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.boot.watch;
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.util.*;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.*;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.service.RetResult;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@RestService(name = "service", catalog = "watch", repair = false)
|
||||||
|
public class ServiceWatchService extends AbstractWatchService {
|
||||||
|
|
||||||
|
@Comment("没有找到目标Service")
|
||||||
|
public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected Application application;
|
||||||
|
|
||||||
|
@RestConvert(type = void.class)
|
||||||
|
@RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容")
|
||||||
|
public RetResult setField(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
|
@RestParam(name = "field", comment = "字段名") String field,
|
||||||
|
@RestParam(name = "value", comment = "字段值") String value) {
|
||||||
|
if (name == null) name = "";
|
||||||
|
if (type == null) type = "";
|
||||||
|
if (field == null) field = "";
|
||||||
|
type = type.trim();
|
||||||
|
field = field.trim();
|
||||||
|
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||||
|
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
|
||||||
|
Object dest = findService(name, type);
|
||||||
|
Class clazz = dest.getClass();
|
||||||
|
Throwable t = null;
|
||||||
|
try {
|
||||||
|
Field fieldObj = null;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
fieldObj = clazz.getDeclaredField(field);
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (t == null) t = e;
|
||||||
|
}
|
||||||
|
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||||
|
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
|
||||||
|
fieldObj.setAccessible(true);
|
||||||
|
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
|
||||||
|
return RetResult.success();
|
||||||
|
} catch (Throwable t2) {
|
||||||
|
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestConvert(type = void.class)
|
||||||
|
@RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容")
|
||||||
|
public RetResult getField(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
|
@RestParam(name = "field", comment = "字段名") String field) {
|
||||||
|
if (name == null) name = "";
|
||||||
|
if (type == null) type = "";
|
||||||
|
if (field == null) field = "";
|
||||||
|
type = type.trim();
|
||||||
|
field = field.trim();
|
||||||
|
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||||
|
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
|
||||||
|
Object dest = findService(name, type);
|
||||||
|
Class clazz = dest.getClass();
|
||||||
|
Throwable t = null;
|
||||||
|
try {
|
||||||
|
Field fieldObj = null;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
fieldObj = clazz.getDeclaredField(field);
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (t == null) t = e;
|
||||||
|
}
|
||||||
|
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||||
|
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
|
||||||
|
fieldObj.setAccessible(true);
|
||||||
|
return new RetResult(fieldObj.get(dest));
|
||||||
|
} catch (Throwable t2) {
|
||||||
|
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestConvert(type = void.class)
|
||||||
|
@RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法")
|
||||||
|
public RetResult runMethod(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
|
@RestParam(name = "method", comment = "Service的方法名") String method,
|
||||||
|
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
|
||||||
|
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
|
||||||
|
if (name == null) name = "";
|
||||||
|
if (type == null) type = "";
|
||||||
|
if (method == null) method = "";
|
||||||
|
type = type.trim();
|
||||||
|
method = method.trim();
|
||||||
|
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||||
|
if (method.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
|
||||||
|
Object dest = findService(name, type);
|
||||||
|
Class clazz = dest.getClass();
|
||||||
|
Throwable t = null;
|
||||||
|
final int paramcount = params == null ? 0 : params.size();
|
||||||
|
if (paramtypes != null && paramcount != paramtypes.size()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
|
||||||
|
try {
|
||||||
|
Method methodObj = null;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
for (Method m : clazz.getDeclaredMethods()) {
|
||||||
|
if (m.getName().equals(method) && m.getParameterCount() == paramcount) {
|
||||||
|
boolean flag = true;
|
||||||
|
if (paramtypes != null) {
|
||||||
|
Class[] pts = m.getParameterTypes();
|
||||||
|
for (int i = 0; i < pts.length; i++) {
|
||||||
|
if (!pts[i].getName().endsWith(paramtypes.get(i))) {
|
||||||
|
flag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
methodObj = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (methodObj != null) break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (t == null) t = e;
|
||||||
|
}
|
||||||
|
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||||
|
if (methodObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")");
|
||||||
|
methodObj.setAccessible(true);
|
||||||
|
if (paramcount < 1) return new RetResult(methodObj.invoke(dest));
|
||||||
|
Object[] paramObjs = new Object[paramcount];
|
||||||
|
Type[] pts = methodObj.getGenericParameterTypes();
|
||||||
|
for (int i = 0; i < paramObjs.length; i++) {
|
||||||
|
paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i));
|
||||||
|
}
|
||||||
|
return new RetResult(methodObj.invoke(dest, paramObjs));
|
||||||
|
} catch (Throwable t2) {
|
||||||
|
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object findService(String name, String type) {
|
||||||
|
Object dest = null;
|
||||||
|
for (NodeServer ns : application.getNodeServers()) {
|
||||||
|
ResourceFactory resFactory = ns.getResourceFactory();
|
||||||
|
List list = resFactory.query((n, s) -> name.equals(n) && s != null && s.getClass().getName().endsWith(type));
|
||||||
|
if (list == null || list.isEmpty()) continue;
|
||||||
|
dest = list.get(0);
|
||||||
|
}
|
||||||
|
if (dest == null) return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
|
||||||
|
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
|
||||||
|
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
|
//待开发
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "reloadService", auth = false, comment = "重新加载Service")
|
||||||
|
public RetResult reloadService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
|
//待开发
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "stopService", auth = false, comment = "动态停止Service")
|
||||||
|
public RetResult stopService(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
|
//待开发
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "findService", auth = false, comment = "查找Service")
|
||||||
|
public RetResult find(@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||||
|
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||||
|
//待开发
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
protected Application application;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected TransportFactory transportFactory;
|
||||||
|
//
|
||||||
|
// @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet")
|
||||||
|
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
|
||||||
|
// //待开发
|
||||||
|
// return RetResult.success();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet")
|
||||||
|
// public RetResult stopServlet(String type) {
|
||||||
|
// //待开发
|
||||||
|
// return RetResult.success();
|
||||||
|
// }
|
||||||
|
}
|
||||||
140
src/main/java/org/redkale/boot/watch/TransportWatchService.java
Normal file
140
src/main/java/org/redkale/boot/watch/TransportWatchService.java
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
protected Application application;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test1", auth = false, comment = "预留")
|
||||||
|
public RetResult test1() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test2", auth = false, comment = "预留")
|
||||||
|
public RetResult test2() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test3", auth = false, comment = "预留")
|
||||||
|
public RetResult test3() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestMapping(name = "test4", auth = false, comment = "预留")
|
||||||
|
public RetResult test4() {
|
||||||
|
return RetResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
327
src/main/java/org/redkale/cluster/CacheClusterAgent.java
Normal file
327
src/main/java/org/redkale/cluster/CacheClusterAgent.java
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.cluster;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.*;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.service.Service;
|
||||||
|
import org.redkale.source.CacheSource;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用CacheSource实现的第三方服务发现管理接口cluster
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.3.0
|
||||||
|
*/
|
||||||
|
public class CacheClusterAgent extends ClusterAgent implements Resourcable {
|
||||||
|
|
||||||
|
@Resource(name = "$")
|
||||||
|
private CacheSource source;
|
||||||
|
|
||||||
|
private String sourceName;
|
||||||
|
|
||||||
|
protected int ttls = 10; //定时检查的秒数
|
||||||
|
|
||||||
|
protected ScheduledThreadPoolExecutor scheduler;
|
||||||
|
|
||||||
|
//可能被HttpMessageClient用到的服务 key: servicename
|
||||||
|
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
//可能被mqtp用到的服务 key: servicename
|
||||||
|
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> mqtpAddressMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(AnyValue config) {
|
||||||
|
super.init(config);
|
||||||
|
this.sourceName = getSourceName();
|
||||||
|
|
||||||
|
AnyValue[] properties = config.getAnyValues("property");
|
||||||
|
for (AnyValue property : properties) {
|
||||||
|
if ("ttls".equalsIgnoreCase(property.getValue("name"))) {
|
||||||
|
this.ttls = Integer.parseInt(property.getValue("value", "").trim());
|
||||||
|
if (this.ttls < 5) this.ttls = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy(AnyValue config) {
|
||||||
|
if (scheduler != null) scheduler.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceName() {
|
||||||
|
AnyValue[] properties = config.getAnyValues("property");
|
||||||
|
for (AnyValue property : properties) {
|
||||||
|
if ("source".equalsIgnoreCase(property.getValue("name"))
|
||||||
|
&& property.getValue("value") != null) {
|
||||||
|
this.sourceName = property.getValue("value");
|
||||||
|
return this.sourceName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resourceName() {
|
||||||
|
return sourceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override //ServiceLoader时判断配置是否符合当前实现类
|
||||||
|
public boolean acceptsConf(AnyValue config) {
|
||||||
|
if (config == null) return false;
|
||||||
|
AnyValue[] properties = config.getAnyValues("property");
|
||||||
|
if (properties == null || properties.length == 0) return false;
|
||||||
|
for (AnyValue property : properties) {
|
||||||
|
if ("source".equalsIgnoreCase(property.getValue("name"))
|
||||||
|
&& property.getValue("value") != null) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
if (this.scheduler == null) {
|
||||||
|
this.scheduler = new ScheduledThreadPoolExecutor(4, (Runnable r) -> {
|
||||||
|
final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Task-Thread");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scheduler.scheduleAtFixedRate(() -> {
|
||||||
|
try {
|
||||||
|
checkApplicationHealth();
|
||||||
|
checkHttpAddressHealth();
|
||||||
|
loadMqtpAddressHealth();
|
||||||
|
localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> {
|
||||||
|
checkLocalHealth(entry);
|
||||||
|
});
|
||||||
|
remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> {
|
||||||
|
updateSncpTransport(entry);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e);
|
||||||
|
}
|
||||||
|
}, Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loadMqtpAddressHealth() {
|
||||||
|
List<String> keys = source.queryKeysStartsWith("cluster.mqtp:");
|
||||||
|
keys.forEach(servicename -> {
|
||||||
|
try {
|
||||||
|
this.mqtpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + servicename + " error", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkHttpAddressHealth() {
|
||||||
|
try {
|
||||||
|
this.httpAddressMap.keySet().stream().forEach(servicename -> {
|
||||||
|
try {
|
||||||
|
this.httpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + servicename + " error", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkLocalHealth(final ClusterEntry entry) {
|
||||||
|
AddressEntry newaddr = new AddressEntry();
|
||||||
|
newaddr.addr = entry.address;
|
||||||
|
newaddr.nodeid = this.nodeid;
|
||||||
|
newaddr.time = System.currentTimeMillis();
|
||||||
|
source.hset(entry.checkname, entry.checkid, AddressEntry.class, newaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override //获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段
|
||||||
|
public CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname) {
|
||||||
|
final Map<String, Collection<InetSocketAddress>> rsmap = new ConcurrentHashMap<>();
|
||||||
|
final String servicenamprefix = generateHttpServiceName(protocol, module, null) + ":";
|
||||||
|
mqtpAddressMap.keySet().stream().filter(k -> k.startsWith(servicenamprefix))
|
||||||
|
.forEach(sn -> rsmap.put(sn.substring(servicenamprefix.length()), mqtpAddressMap.get(sn)));
|
||||||
|
return CompletableFuture.completedFuture(rsmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override //获取HTTP远程服务的可用ip列表
|
||||||
|
public CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
|
||||||
|
final String servicename = generateHttpServiceName(protocol, module, resname);
|
||||||
|
Collection<InetSocketAddress> rs = httpAddressMap.get(servicename);
|
||||||
|
if (rs != null) return CompletableFuture.completedFuture(rs);
|
||||||
|
return queryAddress(servicename).thenApply(t -> {
|
||||||
|
httpAddressMap.put(servicename, t);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompletableFuture<Collection<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
|
||||||
|
return queryAddress(entry.servicename);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Collection<InetSocketAddress>> queryAddress(final String servicename) {
|
||||||
|
final CompletableFuture<Map<String, AddressEntry>> future = source.hmapAsync(servicename, AddressEntry.class, 0, 10000);
|
||||||
|
return future.thenApply(map -> {
|
||||||
|
final Set<InetSocketAddress> set = new HashSet<>();
|
||||||
|
map.forEach((n, v) -> {
|
||||||
|
if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) set.add(v.addr);
|
||||||
|
});
|
||||||
|
return set;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isApplicationHealth() {
|
||||||
|
String servicename = generateApplicationServiceName();
|
||||||
|
String serviceid = generateApplicationServiceId();
|
||||||
|
AddressEntry entry = (AddressEntry) source.hget(servicename, serviceid, AddressEntry.class);
|
||||||
|
return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkApplicationHealth() {
|
||||||
|
String checkname = generateApplicationServiceName();
|
||||||
|
String checkid = generateApplicationCheckId();
|
||||||
|
AddressEntry entry = new AddressEntry();
|
||||||
|
entry.addr = this.appAddress;
|
||||||
|
entry.nodeid = this.nodeid;
|
||||||
|
entry.time = System.currentTimeMillis();
|
||||||
|
source.hset(checkname, checkid, AddressEntry.class, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(Application application) {
|
||||||
|
if (isApplicationHealth()) throw new RuntimeException("application.nodeid=" + nodeid + " exists in cluster");
|
||||||
|
deregister(application);
|
||||||
|
|
||||||
|
String serviceid = generateApplicationServiceId();
|
||||||
|
String servicename = generateApplicationServiceName();
|
||||||
|
AddressEntry entry = new AddressEntry();
|
||||||
|
entry.addr = this.appAddress;
|
||||||
|
entry.nodeid = this.nodeid;
|
||||||
|
entry.time = System.currentTimeMillis();
|
||||||
|
source.hset(servicename, serviceid, AddressEntry.class, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deregister(Application application) {
|
||||||
|
String servicename = generateApplicationServiceName();
|
||||||
|
source.remove(servicename);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ClusterEntry register(NodeServer ns, String protocol, Service service) {
|
||||||
|
deregister(ns, protocol, service, false);
|
||||||
|
//
|
||||||
|
ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service);
|
||||||
|
AddressEntry entry = new AddressEntry();
|
||||||
|
entry.addr = clusterEntry.address;
|
||||||
|
entry.nodeid = this.nodeid;
|
||||||
|
entry.time = System.currentTimeMillis();
|
||||||
|
source.hset(clusterEntry.servicename, clusterEntry.serviceid, AddressEntry.class, entry);
|
||||||
|
return clusterEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deregister(NodeServer ns, String protocol, Service service) {
|
||||||
|
deregister(ns, protocol, service, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) {
|
||||||
|
String servicename = generateServiceName(ns, protocol, service);
|
||||||
|
String serviceid = generateServiceId(ns, protocol, service);
|
||||||
|
ClusterEntry currEntry = null;
|
||||||
|
for (final ClusterEntry entry : localEntrys.values()) {
|
||||||
|
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) {
|
||||||
|
currEntry = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currEntry == null) {
|
||||||
|
for (final ClusterEntry entry : remoteEntrys.values()) {
|
||||||
|
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) {
|
||||||
|
currEntry = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
source.hremove(servicename, serviceid);
|
||||||
|
if (realcanceled && currEntry != null) currEntry.canceled = true;
|
||||||
|
if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) {
|
||||||
|
deregister(ns, "mqtp", service, realcanceled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String generateApplicationServiceName() {
|
||||||
|
return "cluster." + super.generateApplicationServiceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
|
||||||
|
return "cluster." + super.generateServiceName(ns, protocol, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateHttpServiceName(String protocol, String module, String resname) {
|
||||||
|
return "cluster." + super.generateHttpServiceName(protocol, module, resname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String generateApplicationCheckName() {
|
||||||
|
return generateApplicationServiceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String generateApplicationCheckId() {
|
||||||
|
return generateApplicationServiceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
|
||||||
|
return generateServiceName(ns, protocol, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String generateCheckId(NodeServer ns, String protocol, Service service) {
|
||||||
|
return generateServiceId(ns, protocol, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AddressEntry {
|
||||||
|
|
||||||
|
public InetSocketAddress addr;
|
||||||
|
|
||||||
|
public int nodeid;
|
||||||
|
|
||||||
|
public long time;
|
||||||
|
|
||||||
|
public AddressEntry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressEntry refresh() {
|
||||||
|
this.time = System.currentTimeMillis();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonConvert.root().convertTo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
342
src/main/java/org/redkale/cluster/ClusterAgent.java
Normal file
342
src/main/java/org/redkale/cluster/ClusterAgent.java
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.cluster;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.redkale.boot.*;
|
||||||
|
import static org.redkale.boot.Application.*;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.mq.MessageMultiConsumer;
|
||||||
|
import org.redkale.net.*;
|
||||||
|
import org.redkale.net.http.*;
|
||||||
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.service.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方服务发现管理接口cluster
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.1.0
|
||||||
|
*/
|
||||||
|
public abstract class ClusterAgent {
|
||||||
|
|
||||||
|
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
|
|
||||||
|
@Resource(name = RESNAME_APP_NODEID)
|
||||||
|
protected int nodeid;
|
||||||
|
|
||||||
|
@Resource(name = RESNAME_APP_NAME)
|
||||||
|
protected String appName = "";
|
||||||
|
|
||||||
|
@Resource(name = RESNAME_APP_ADDR)
|
||||||
|
protected InetSocketAddress appAddress;
|
||||||
|
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
protected boolean waits;
|
||||||
|
|
||||||
|
protected String[] protocols; //必须全大写
|
||||||
|
|
||||||
|
protected int[] ports;
|
||||||
|
|
||||||
|
protected AnyValue config;
|
||||||
|
|
||||||
|
protected TransportFactory transportFactory;
|
||||||
|
|
||||||
|
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public void init(AnyValue config) {
|
||||||
|
this.config = config;
|
||||||
|
this.name = config.getValue("name", "");
|
||||||
|
this.waits = config.getBoolValue("waits", false);
|
||||||
|
{
|
||||||
|
String ps = config.getValue("protocols", "").toUpperCase();
|
||||||
|
if (ps == null || ps.isEmpty()) ps = "SNCP;HTTP";
|
||||||
|
this.protocols = ps.split(";");
|
||||||
|
}
|
||||||
|
String ts = config.getValue("ports", "");
|
||||||
|
if (ts != null && !ts.isEmpty()) {
|
||||||
|
String[] its = ts.split(";");
|
||||||
|
List<Integer> list = new ArrayList<>();
|
||||||
|
for (String str : its) {
|
||||||
|
if (str.trim().isEmpty()) continue;
|
||||||
|
list.add(Integer.parseInt(str.trim()));
|
||||||
|
}
|
||||||
|
if (!list.isEmpty()) this.ports = list.stream().mapToInt(x -> x).toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy(AnyValue config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//ServiceLoader时判断配置是否符合当前实现类
|
||||||
|
public abstract boolean acceptsConf(AnyValue config);
|
||||||
|
|
||||||
|
public boolean containsProtocol(String protocol) {
|
||||||
|
if (protocol == null || protocol.isEmpty()) return false;
|
||||||
|
return protocols == null || Utility.contains(protocols, protocol.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsPort(int port) {
|
||||||
|
if (ports == null || ports.length == 0) return true;
|
||||||
|
return Utility.contains(ports, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void register(Application application);
|
||||||
|
|
||||||
|
public abstract void deregister(Application application);
|
||||||
|
|
||||||
|
//注册服务, 在NodeService调用Service.init方法之前调用
|
||||||
|
public void register(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
|
||||||
|
if (localServices.isEmpty()) return;
|
||||||
|
//注册本地模式
|
||||||
|
for (Service service : localServices) {
|
||||||
|
if (!canRegister(protocol, service)) continue;
|
||||||
|
ClusterEntry htentry = register(ns, protocol, service);
|
||||||
|
localEntrys.put(htentry.serviceid, htentry);
|
||||||
|
if (protocol.toLowerCase().startsWith("http")) {
|
||||||
|
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
|
||||||
|
if (mmc != null) {
|
||||||
|
ClusterEntry mqentry = register(ns, "mqtp", service);
|
||||||
|
localEntrys.put(mqentry.serviceid, mqentry);
|
||||||
|
htentry.submqtp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//远程模式加载IP列表, 只支持SNCP协议
|
||||||
|
if (ns.isSNCP()) {
|
||||||
|
for (Service service : remoteServices) {
|
||||||
|
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
|
||||||
|
updateSncpTransport(entry);
|
||||||
|
remoteEntrys.put(entry.serviceid, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//注销服务, 在NodeService调用Service.destroy 方法之前调用
|
||||||
|
public void deregister(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
|
||||||
|
//注销本地模式 远程模式不注册
|
||||||
|
for (Service service : localServices) {
|
||||||
|
if (!canRegister(protocol, service)) continue;
|
||||||
|
deregister(ns, protocol, service);
|
||||||
|
}
|
||||||
|
afterDeregister(ns, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean canRegister(String protocol, Service service) {
|
||||||
|
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) return false;
|
||||||
|
AutoLoad al = service.getClass().getAnnotation(AutoLoad.class);
|
||||||
|
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return false;
|
||||||
|
if (service instanceof WebSocketNode) {
|
||||||
|
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void afterDeregister(NodeServer ns, String protocol) {
|
||||||
|
if (!this.waits) return;
|
||||||
|
int s = intervalCheckSeconds();
|
||||||
|
if (s > 0) { //暂停,弥补其他依赖本进程服务的周期偏差
|
||||||
|
try {
|
||||||
|
Thread.sleep(s * 1000);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
}
|
||||||
|
logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int intervalCheckSeconds() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段
|
||||||
|
public abstract CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname);
|
||||||
|
|
||||||
|
//获取HTTP远程服务的可用ip列表
|
||||||
|
public abstract CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname);
|
||||||
|
|
||||||
|
//获取远程服务的可用ip列表
|
||||||
|
protected abstract CompletableFuture<Collection<InetSocketAddress>> queryAddress(ClusterEntry entry);
|
||||||
|
|
||||||
|
//注册服务
|
||||||
|
protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service);
|
||||||
|
|
||||||
|
//注销服务
|
||||||
|
protected abstract void deregister(NodeServer ns, String protocol, Service service);
|
||||||
|
|
||||||
|
//格式: protocol:classtype-resourcename
|
||||||
|
protected void updateSncpTransport(ClusterEntry entry) {
|
||||||
|
Service service = entry.serviceref.get();
|
||||||
|
if (service == null) return;
|
||||||
|
Collection<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
|
||||||
|
Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netprotocol, entry.address, null, addrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateApplicationServiceName() {
|
||||||
|
return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node" + this.nodeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateApplicationServiceId() { //与servicename相同
|
||||||
|
return generateApplicationServiceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateApplicationCheckName() {
|
||||||
|
return "check-" + generateApplicationServiceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateApplicationCheckId() {
|
||||||
|
return "check-" + generateApplicationServiceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
//也会提供给HttpMessageClusterAgent适用
|
||||||
|
public String generateHttpServiceName(String protocol, String module, String resname) {
|
||||||
|
return protocol.toLowerCase() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: protocol:classtype-resourcename
|
||||||
|
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
|
||||||
|
if (protocol.toLowerCase().startsWith("http")) { //HTTP使用RestService.name方式是为了与MessageClient中的module保持一致, 因为HTTP依靠的url中的module,无法知道Service类名
|
||||||
|
String resname = Sncp.getResourceName(service);
|
||||||
|
String module = Rest.getRestModule(service).toLowerCase();
|
||||||
|
return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname));
|
||||||
|
}
|
||||||
|
if ("mqtp".equalsIgnoreCase(protocol)) {
|
||||||
|
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
|
||||||
|
String selfmodule = Rest.getRestModule(service).toLowerCase();
|
||||||
|
return protocol.toLowerCase() + ":" + mmc.module() + ":" + selfmodule;
|
||||||
|
}
|
||||||
|
if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName();
|
||||||
|
String resname = Sncp.getResourceName(service);
|
||||||
|
return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname));
|
||||||
|
}
|
||||||
|
|
||||||
|
//格式: protocol:classtype-resourcename:nodeid
|
||||||
|
protected String generateServiceId(NodeServer ns, String protocol, Service service) {
|
||||||
|
return generateServiceName(ns, protocol, service) + ":" + this.nodeid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
|
||||||
|
return "check-" + generateServiceName(ns, protocol, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateCheckId(NodeServer ns, String protocol, Service service) {
|
||||||
|
return "check-" + generateServiceId(ns, protocol, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() {
|
||||||
|
return localEntrys;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() {
|
||||||
|
return remoteEntrys;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonConvert.root().convertTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportFactory getTransportFactory() {
|
||||||
|
return transportFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransportFactory(TransportFactory transportFactory) {
|
||||||
|
this.transportFactory = transportFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getProtocols() {
|
||||||
|
return protocols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProtocols(String[] protocols) {
|
||||||
|
this.protocols = protocols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getPorts() {
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPorts(int[] ports) {
|
||||||
|
this.ports = ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnyValue getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfig(AnyValue config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClusterEntry {
|
||||||
|
|
||||||
|
public String serviceid;
|
||||||
|
|
||||||
|
public String servicename;
|
||||||
|
|
||||||
|
public String checkid;
|
||||||
|
|
||||||
|
public String checkname;
|
||||||
|
|
||||||
|
public String protocol;
|
||||||
|
|
||||||
|
public String netprotocol;
|
||||||
|
|
||||||
|
public WeakReference<Service> serviceref;
|
||||||
|
|
||||||
|
public InetSocketAddress address;
|
||||||
|
|
||||||
|
public boolean canceled;
|
||||||
|
|
||||||
|
public boolean submqtp;
|
||||||
|
|
||||||
|
public ClusterEntry(NodeServer ns, String protocol, Service service) {
|
||||||
|
this.serviceid = generateServiceId(ns, protocol, service);
|
||||||
|
this.servicename = generateServiceName(ns, protocol, service);
|
||||||
|
this.checkid = generateCheckId(ns, protocol, service);
|
||||||
|
this.checkname = generateCheckName(ns, protocol, service);
|
||||||
|
this.protocol = protocol;
|
||||||
|
InetSocketAddress addr = ns.getSocketAddress();
|
||||||
|
String host = addr.getHostString();
|
||||||
|
if ("0.0.0.0".equals(host)) {
|
||||||
|
host = appAddress.getHostString();
|
||||||
|
addr = new InetSocketAddress(host, addr.getPort());
|
||||||
|
}
|
||||||
|
this.address = addr;
|
||||||
|
this.serviceref = new WeakReference(service);
|
||||||
|
Server server = ns.getServer();
|
||||||
|
this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonConvert.root().convertTo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/java/org/redkale/cluster/ClusterAgentProvider.java
Normal file
25
src/main/java/org/redkale/cluster/ClusterAgentProvider.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.cluster;
|
||||||
|
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义的ClusterAgent加载器
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public interface ClusterAgentProvider {
|
||||||
|
|
||||||
|
public boolean acceptsConf(AnyValue config);
|
||||||
|
|
||||||
|
public Class<? extends ClusterAgent> agentClass();
|
||||||
|
}
|
||||||
64
src/main/java/org/redkale/convert/AnyDecoder.java
Normal file
64
src/main/java/org/redkale/convert/AnyDecoder.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
import org.redkale.convert.Reader.ValueType;
|
||||||
|
import static org.redkale.convert.Reader.ValueType.MAP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对不明类型的对象进行反序列化。 <br>
|
||||||
|
* <b>注意: 目前只支持文本格式</b> <br>
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class AnyDecoder implements Decodeable<Reader, Object> {
|
||||||
|
|
||||||
|
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
|
||||||
|
|
||||||
|
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
|
||||||
|
|
||||||
|
protected final Decodeable<Reader, String> stringDecoder;
|
||||||
|
|
||||||
|
protected final CollectionDecoder collectionDecoder;
|
||||||
|
|
||||||
|
protected final MapDecoder mapDecoder;
|
||||||
|
|
||||||
|
public AnyDecoder(final ConvertFactory factory) {
|
||||||
|
this.stringDecoder = factory.loadDecoder(String.class);
|
||||||
|
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
|
||||||
|
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertFrom(Reader in) {
|
||||||
|
ValueType vt = in.readType();
|
||||||
|
if (vt == null) return null;
|
||||||
|
switch (vt) {
|
||||||
|
case ARRAY:
|
||||||
|
return this.collectionDecoder.convertFrom(in);
|
||||||
|
case MAP:
|
||||||
|
return this.mapDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
return this.stringDecoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return void.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
73
src/main/java/org/redkale/convert/AnyEncoder.java
Normal file
73
src/main/java/org/redkale/convert/AnyEncoder.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入Writer,JSON则不写入。
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 序列化的泛型类型
|
||||||
|
*/
|
||||||
|
public final class AnyEncoder<T> implements Encodeable<Writer, T> {
|
||||||
|
|
||||||
|
final ConvertFactory factory;
|
||||||
|
|
||||||
|
AnyEncoder(ConvertFactory factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void convertTo(final Writer out, final T value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeClassName(null);
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
Class clazz = value.getClass();
|
||||||
|
if (clazz == Object.class) {
|
||||||
|
out.writeObjectB(value);
|
||||||
|
out.writeObjectE(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clazz));
|
||||||
|
factory.loadEncoder(clazz).convertTo(out, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void convertMapTo(final Writer out, final Object... values) {
|
||||||
|
if (values == null) {
|
||||||
|
out.writeNull();
|
||||||
|
} else {
|
||||||
|
int count = values.length - values.length % 2;
|
||||||
|
if (out.writeMapB(count / 2, (Encodeable) this, (Encodeable) this, values) < 0) {
|
||||||
|
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
|
||||||
|
public Type getType() {
|
||||||
|
return Object.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
src/main/java/org/redkale/convert/AnyValueDecoder.java
Normal file
40
src/main/java/org/redkale/convert/AnyValueDecoder.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AnyValue的Decoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类型
|
||||||
|
*
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class AnyValueDecoder<R extends Reader> implements Decodeable<R, AnyValue> {
|
||||||
|
|
||||||
|
protected final ConvertFactory factory;
|
||||||
|
|
||||||
|
public AnyValueDecoder(final ConvertFactory factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnyValue convertFrom(R in) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return AnyValue.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
33
src/main/java/org/redkale/convert/AnyValueEncoder.java
Normal file
33
src/main/java/org/redkale/convert/AnyValueEncoder.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AnyValue的Encoder实现
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <W> Writer输出的子类
|
||||||
|
*
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class AnyValueEncoder<W extends Writer> implements Encodeable<W, AnyValue> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(W out, AnyValue value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return AnyValue.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,19 +20,19 @@ import java.util.*;
|
|||||||
* @param <T> 反解析的数组元素类型
|
* @param <T> 反解析的数组元素类型
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
||||||
|
|
||||||
private final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
private final Type componentType;
|
protected final Type componentType;
|
||||||
|
|
||||||
private final Class componentClass;
|
protected final Class componentClass;
|
||||||
|
|
||||||
protected final Decodeable<Reader, T> decoder;
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
private boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
public ArrayDecoder(final ConvertFactory factory, final Type type) {
|
public ArrayDecoder(final ConvertFactory factory, final Type type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@@ -51,7 +51,7 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
this.componentClass = (Class) this.componentType;
|
this.componentClass = (Class) this.componentType;
|
||||||
}
|
}
|
||||||
factory.register(type, this);
|
factory.register(type, this);
|
||||||
this.decoder = factory.loadDecoder(this.componentType);
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@@ -62,9 +62,19 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T[] convertFrom(Reader in) {
|
public T[] convertFrom(Reader in) {
|
||||||
final int len = in.readArrayB();
|
return convertFrom(in, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T[] convertFrom(Reader in, DeMember member) {
|
||||||
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||||
|
int contentLength = -1;
|
||||||
if (len == Reader.SIGN_NULL) return null;
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
if (this.decoder == null) {
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||||
|
len = Reader.SIGN_NOLENGTH;
|
||||||
|
}
|
||||||
|
if (this.componentDecoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -75,11 +85,16 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Decodeable<Reader, T> localdecoder = this.decoder;
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
final List<T> result = new ArrayList();
|
final List<T> result = new ArrayList();
|
||||||
|
boolean first = true;
|
||||||
if (len == Reader.SIGN_NOLENGTH) {
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
while (in.hasNext()) {
|
int startPosition = in.position();
|
||||||
result.add(localdecoder.convertFrom(in));
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
|
if (itemReader == null) break;
|
||||||
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
@@ -91,9 +106,26 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
return result.toArray(rs);
|
return result.toArray(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
|
||||||
|
return in.hasNext(startPosition, contentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
|
if (in == null) return null;
|
||||||
|
return decoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
|
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,4 +133,12 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
|
return componentDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
133
src/main/java/org/redkale/convert/ArrayEncoder.java
Normal file
133
src/main/java/org/redkale/convert/ArrayEncoder.java
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数组的序列化操作类 <br>
|
||||||
|
* 对象数组的序列化,不包含int[]、long[]这样的primitive class数组。 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 序列化的数组元素类型
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
|
||||||
|
|
||||||
|
protected final Type type;
|
||||||
|
|
||||||
|
protected final Type componentType;
|
||||||
|
|
||||||
|
protected final Encodeable anyEncoder;
|
||||||
|
|
||||||
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
|
protected final boolean subtypefinal;
|
||||||
|
|
||||||
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
|
public ArrayEncoder(final ConvertFactory factory, final Type type) {
|
||||||
|
this.type = type;
|
||||||
|
try {
|
||||||
|
if (type instanceof GenericArrayType) {
|
||||||
|
Type t = ((GenericArrayType) type).getGenericComponentType();
|
||||||
|
this.componentType = t instanceof TypeVariable ? Object.class : t;
|
||||||
|
} else if ((type instanceof Class) && ((Class) type).isArray()) {
|
||||||
|
this.componentType = ((Class) type).getComponentType();
|
||||||
|
} else {
|
||||||
|
throw new ConvertException("(" + type + ") is not a array type");
|
||||||
|
}
|
||||||
|
factory.register(type, this);
|
||||||
|
this.componentEncoder = factory.loadEncoder(this.componentType);
|
||||||
|
this.anyEncoder = factory.getAnyEncoder();
|
||||||
|
this.subtypefinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers());
|
||||||
|
} finally {
|
||||||
|
inited = true;
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertTo(Writer out, T[] value) {
|
||||||
|
convertTo(out, null, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convertTo(Writer out, EnMember member, T[] value) {
|
||||||
|
if (value == null) {
|
||||||
|
out.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int iMax = value.length - 1;
|
||||||
|
if (iMax == -1) {
|
||||||
|
out.writeArrayB(0, this, componentEncoder, value);
|
||||||
|
out.writeArrayE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.componentEncoder == null) {
|
||||||
|
if (!this.inited) {
|
||||||
|
synchronized (lock) {
|
||||||
|
try {
|
||||||
|
lock.wait();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Encodeable<Writer, Object> itemEncoder = this.componentEncoder;
|
||||||
|
if (subtypefinal) {
|
||||||
|
if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) {
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
writeMemberValue(out, member, itemEncoder, value[i], i);
|
||||||
|
if (i == iMax) break;
|
||||||
|
out.writeArrayMark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) {
|
||||||
|
final Type comp = this.componentType;
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
Object v = value[i];
|
||||||
|
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? itemEncoder : anyEncoder), v, i);
|
||||||
|
if (i == iMax) break;
|
||||||
|
out.writeArrayMark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.writeArrayE();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeMemberValue(Writer out, EnMember member, Encodeable<Writer, Object> encoder, Object value, int index) {
|
||||||
|
encoder.convertTo(out, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
|
return componentEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
src/main/java/org/redkale/convert/BinaryConvert.java
Normal file
35
src/main/java/org/redkale/convert/BinaryConvert.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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
149
src/main/java/org/redkale/convert/CollectionDecoder.java
Normal file
149
src/main/java/org/redkale/convert/CollectionDecoder.java
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import org.redkale.util.Creator;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection的反序列化操作类 <br>
|
||||||
|
* 支持一定程度的泛型。 <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> 反解析的集合元素类型
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
|
||||||
|
|
||||||
|
protected final Type type;
|
||||||
|
|
||||||
|
protected final Type componentType;
|
||||||
|
|
||||||
|
protected Creator<Collection<T>> creator;
|
||||||
|
|
||||||
|
protected final Decodeable<Reader, T> componentDecoder;
|
||||||
|
|
||||||
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
|
public CollectionDecoder(final ConvertFactory factory, final Type type) {
|
||||||
|
this.type = type;
|
||||||
|
try {
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
final ParameterizedType pt = (ParameterizedType) type;
|
||||||
|
this.componentType = pt.getActualTypeArguments()[0];
|
||||||
|
this.creator = factory.loadCreator((Class) pt.getRawType());
|
||||||
|
factory.register(type, this);
|
||||||
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
|
} else if (factory.isReversible()) {
|
||||||
|
this.componentType = Object.class;
|
||||||
|
this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class);
|
||||||
|
factory.register(type, this);
|
||||||
|
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||||
|
} else {
|
||||||
|
throw new ConvertException("CollectionDecoder not support the type (" + type + ")");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inited = true;
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//仅供类似JsonAnyDecoder这种动态创建使用, 不得调用 factory.register
|
||||||
|
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
|
||||||
|
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
|
||||||
|
Objects.requireNonNull(componentDecoder);
|
||||||
|
this.type = type;
|
||||||
|
this.componentType = componentType;
|
||||||
|
this.creator = creator;
|
||||||
|
this.componentDecoder = componentDecoder;
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<T> convertFrom(Reader in) {
|
||||||
|
return convertFrom(in, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<T> convertFrom(Reader in, DeMember member) {
|
||||||
|
byte[] typevals = new byte[1];
|
||||||
|
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||||
|
int contentLength = -1;
|
||||||
|
if (len == Reader.SIGN_NULL) return null;
|
||||||
|
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||||
|
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||||
|
len = Reader.SIGN_NOLENGTH;
|
||||||
|
}
|
||||||
|
if (this.componentDecoder == null) {
|
||||||
|
if (!this.inited) {
|
||||||
|
synchronized (lock) {
|
||||||
|
try {
|
||||||
|
lock.wait();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||||
|
final Collection<T> result = this.creator.create();
|
||||||
|
boolean first = true;
|
||||||
|
if (len == Reader.SIGN_NOLENGTH) {
|
||||||
|
int startPosition = in.position();
|
||||||
|
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||||
|
Reader itemReader = getItemReader(in, member, first);
|
||||||
|
if (itemReader == null) break;
|
||||||
|
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
result.add(localdecoder.convertFrom(in));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.readArrayE();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
|
||||||
|
return in.hasNext(startPosition, contentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||||
|
if (in == null) return null;
|
||||||
|
return decoder.convertFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Decodeable<Reader, T> getComponentDecoder() {
|
||||||
|
return componentDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,15 +19,15 @@ import java.util.Collection;
|
|||||||
* @param <T> 序列化的集合元素类型
|
* @param <T> 序列化的集合元素类型
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
|
||||||
|
|
||||||
private final Type type;
|
protected final Type type;
|
||||||
|
|
||||||
private final Encodeable<Writer, Object> encoder;
|
protected final Encodeable<Writer, Object> componentEncoder;
|
||||||
|
|
||||||
private boolean inited = false;
|
protected volatile boolean inited = false;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
public CollectionEncoder(final ConvertFactory factory, final Type type) {
|
public CollectionEncoder(final ConvertFactory factory, final Type type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@@ -35,12 +35,12 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
|
|||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
if (t instanceof TypeVariable) {
|
if (t instanceof TypeVariable) {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.loadEncoder(t);
|
this.componentEncoder = factory.loadEncoder(t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.encoder = factory.getAnyEncoder();
|
this.componentEncoder = factory.getAnyEncoder();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
inited = true;
|
inited = true;
|
||||||
@@ -52,16 +52,20 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void convertTo(Writer out, Collection<T> value) {
|
public void convertTo(Writer out, Collection<T> value) {
|
||||||
|
convertTo(out, null, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convertTo(Writer out, EnMember member, Collection<T> value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (value.isEmpty()) {
|
if (value.isEmpty()) {
|
||||||
out.writeArrayB(0);
|
out.writeArrayB(0, this, componentEncoder, value);
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.encoder == null) {
|
if (this.componentEncoder == null) {
|
||||||
if (!this.inited) {
|
if (!this.inited) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try {
|
try {
|
||||||
@@ -72,18 +76,36 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.writeArrayB(value.size());
|
if (out.writeArrayB(value.size(), this, componentEncoder, value) < 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Object v : value) {
|
for (Object v : value) {
|
||||||
if (!first) out.writeArrayMark();
|
if (!first) out.writeArrayMark();
|
||||||
encoder.convertTo(out, v);
|
writeMemberValue(out, member, v, first);
|
||||||
if (first) first = false;
|
if (first) first = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
out.writeArrayE();
|
out.writeArrayE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
|
||||||
|
componentEncoder.convertTo(out, value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Encodeable<Writer, Object> getComponentEncoder() {
|
||||||
|
return componentEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getComponentType() {
|
||||||
|
return componentEncoder == null ? null : componentEncoder.getType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
80
src/main/java/org/redkale/convert/Convert.java
Normal file
80
src/main/java/org/redkale/convert/Convert.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.function.*;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列化/反序列化操作类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <R> Reader输入的子类
|
||||||
|
* @param <W> Writer输出的子类
|
||||||
|
*/
|
||||||
|
public abstract class Convert<R extends Reader, W extends Writer> {
|
||||||
|
|
||||||
|
protected final ConvertFactory<R, W> factory;
|
||||||
|
|
||||||
|
protected Convert(ConvertFactory<R, W> factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConvertFactory<R, W> getFactory() {
|
||||||
|
return this.factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S configWrite(S writer) {
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||||
|
writer.objFieldFunc = objFieldFunc;
|
||||||
|
writer.objExtFunc = objExtFunc;
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
|
||||||
|
|
||||||
|
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
|
||||||
|
|
||||||
|
public abstract boolean isBinary();
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
|
||||||
|
|
||||||
|
//@since 2.2.0
|
||||||
|
public abstract <T> T convertFrom(final Type type, final byte[] bytes, final int offset, final int length);
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
|
||||||
|
|
||||||
|
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
|
||||||
|
|
||||||
|
public abstract void convertTo(final W writer, final Object value);
|
||||||
|
|
||||||
|
public abstract void convertTo(final W writer, final Type type, final Object value);
|
||||||
|
|
||||||
|
public abstract byte[] convertToBytes(final Object value);
|
||||||
|
|
||||||
|
public abstract byte[] convertToBytes(final Type type, final Object value);
|
||||||
|
|
||||||
|
public abstract void convertToBytes(final Object value, final ConvertBytesHandler handler);
|
||||||
|
|
||||||
|
public abstract void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler);
|
||||||
|
|
||||||
|
public abstract void convertToBytes(final ByteArray array, final Object value);
|
||||||
|
|
||||||
|
public abstract void convertToBytes(final ByteArray array, final Type type, final Object value);
|
||||||
|
|
||||||
|
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value);
|
||||||
|
|
||||||
|
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value);
|
||||||
|
|
||||||
|
}
|
||||||
23
src/main/java/org/redkale/convert/ConvertBytesHandler.java
Normal file
23
src/main/java/org/redkale/convert/ConvertBytesHandler.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.convert;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* convertToBytes系列的方法的回调
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*
|
||||||
|
* @since 2.3.0
|
||||||
|
*/
|
||||||
|
public interface ConvertBytesHandler {
|
||||||
|
|
||||||
|
<A> void completed(byte[] bs, int offset, int length, Consumer<A> callback, A attachment);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user