354 Commits

Author SHA1 Message Date
Redkale
0ec2bf211a 2017-05-31 10:51:02 +08:00
Redkale
b3c54e4db5 2017-05-31 10:50:10 +08:00
Redkale
52838f04a9 2017-05-31 08:31:40 +08:00
Redkale
fa5bd95a2b 2017-05-30 17:12:51 +08:00
Redkale
b2e73d378c 2017-05-30 16:42:10 +08:00
Redkale
6895b31ad0 2017-05-30 16:11:29 +08:00
Redkale
56637ff7ef 2017-05-30 16:04:25 +08:00
Redkale
40b46f9c7f 2017-05-30 14:57:58 +08:00
Redkale
0aed26652d 2017-05-30 11:12:42 +08:00
Redkale
14238a0203 2017-05-30 07:22:45 +08:00
Redkale
369a70e857 2017-05-29 21:20:30 +08:00
Redkale
6ede9b0f31 2017-05-29 21:19:52 +08:00
Redkale
6c039dc8f4 2017-05-29 21:01:56 +08:00
Redkale
1e69a6755f 2017-05-29 19:02:43 +08:00
Redkale
f6c617574c 2017-05-29 17:22:12 +08:00
Redkale
2291beb5e7 2017-05-29 16:35:11 +08:00
Redkale
d8e091f888 2017-05-29 15:13:46 +08:00
Redkale
6a42ae7570 2017-05-29 15:05:39 +08:00
Redkale
756e4634d9 2017-05-29 15:03:27 +08:00
Redkale
06773ccdc0 2017-05-29 14:03:11 +08:00
Redkale
0da74be2fa 2017-05-29 09:17:54 +08:00
Redkale
1d1b732a74 2017-05-28 15:04:10 +08:00
Redkale
ab90c80785 2017-05-28 13:30:50 +08:00
Redkale
6cd232efd2 2017-05-28 10:19:56 +08:00
Redkale
96e4b8834d 2017-05-27 21:56:34 +08:00
Redkale
7ef5ddfd46 2017-05-27 21:41:24 +08:00
Redkale
73a973e0ed 2017-05-27 21:05:17 +08:00
Redkale
e0411a94f6 2017-05-27 20:44:47 +08:00
Redkale
054e853074 2017-05-27 19:34:35 +08:00
Redkale
88672b5522 2017-05-27 18:20:49 +08:00
Redkale
0a60b81a98 2017-05-27 18:08:14 +08:00
Redkale
37f8208b1b 2017-05-27 17:54:55 +08:00
Redkale
a8b9cc9753 2017-05-27 15:31:35 +08:00
Redkale
a99c7d3454 2017-05-27 15:07:24 +08:00
Redkale
b88987dd98 2017-05-27 14:59:52 +08:00
Redkale
54f4f8e35d 2017-05-27 13:18:32 +08:00
Redkale
97670261e6 2017-05-27 12:43:03 +08:00
Redkale
82a2a513f5 2017-05-27 12:31:58 +08:00
Redkale
174a8a2a0c 2017-05-27 11:54:28 +08:00
Redkale
92b3d0bbd4 2017-05-27 10:25:53 +08:00
Redkale
24c90b015a 2017-05-26 14:19:34 +08:00
Redkale
2742e935cb 2017-05-26 13:57:50 +08:00
Redkale
b7770c89b8 2017-05-26 13:52:36 +08:00
Redkale
779a9cca4d 2017-05-26 13:26:39 +08:00
Redkale
493c27beb5 2017-05-26 13:25:57 +08:00
Redkale
c68d988d51 2017-05-26 11:15:04 +08:00
Redkale
ceeb924d4d 2017-05-26 10:18:55 +08:00
Redkale
4d0a16d35d 2017-05-26 07:39:41 +08:00
Redkale
1e60adf5bb 2017-05-26 00:40:51 +08:00
Redkale
59b08684a8 2017-05-25 23:51:27 +08:00
Redkale
c326b7ed05 2017-05-25 23:06:27 +08:00
Redkale
d9bf5c8412 2017-05-25 17:54:14 +08:00
Redkale
39d4e6405f 2017-05-25 17:43:22 +08:00
Redkale
03bcea30df 2017-05-25 17:18:20 +08:00
Redkale
27b67cde0e 2017-05-25 16:50:46 +08:00
Redkale
31fca5630b 2017-05-25 16:49:01 +08:00
Redkale
3504d735c1 2017-05-25 16:01:11 +08:00
Redkale
74f554fe33 2017-05-25 15:57:18 +08:00
Redkale
b02d4e6731 2017-05-25 15:06:15 +08:00
Redkale
23fd72b116 2017-05-24 23:05:14 +08:00
Redkale
4cd1b10c35 2017-05-24 22:54:11 +08:00
Redkale
71c0763304 2017-05-24 17:57:23 +08:00
Redkale
0ea4ddb5eb 2017-05-24 17:50:49 +08:00
Redkale
9bc266ca61 2017-05-24 12:36:38 +08:00
Redkale
b202de4916 2017-05-24 10:53:51 +08:00
Redkale
7d26198e88 2017-05-24 09:29:14 +08:00
Redkale
d98e249fd7 2017-05-24 09:21:30 +08:00
Redkale
7a8b6cac9d 2017-05-23 23:23:08 +08:00
Redkale
822ac078b5 2017-05-23 23:19:16 +08:00
Redkale
5e3718af19 2017-05-23 23:16:37 +08:00
Redkale
713fdefb56 2017-05-23 23:14:30 +08:00
Redkale
804e0e27e7 2017-05-23 22:14:03 +08:00
Redkale
2653808f8f 2017-05-23 22:12:55 +08:00
Redkale
ba12df2cba 2017-05-23 20:12:32 +08:00
Redkale
d2bfa9ab56 2017-05-23 20:03:09 +08:00
Redkale
0fb108bd9b 2017-05-23 19:59:14 +08:00
Redkale
145527db38 2017-05-23 19:45:52 +08:00
Redkale
d7c50532cf 2017-05-23 18:59:56 +08:00
Redkale
6562ac0a2b 2017-05-23 14:25:24 +08:00
Redkale
6f4c9dca48 2017-05-23 13:15:13 +08:00
Redkale
f18ef4f94d 2017-05-23 12:19:42 +08:00
Redkale
4786e17243 2017-05-23 11:23:58 +08:00
Redkale
96beb9cef4 2017-05-23 11:04:54 +08:00
Redkale
a59bf92ee7 2017-05-23 09:32:52 +08:00
Redkale
cdc3dbf9ea 2017-05-22 22:21:17 +08:00
Redkale
a957a18e32 2017-05-22 22:18:03 +08:00
Redkale
95c53f99e0 2017-05-22 20:20:29 +08:00
Redkale
03ac849451 2017-05-22 20:01:52 +08:00
Redkale
d9946ceb64 2017-05-22 19:32:26 +08:00
Redkale
fda9c30dc4 2017-05-22 19:22:24 +08:00
Redkale
205162ce38 2017-05-22 17:13:16 +08:00
Redkale
f5379df63b 2017-05-22 16:47:53 +08:00
Redkale
859e56af4d 2017-05-22 16:46:59 +08:00
Redkale
a29cc94f32 2017-05-22 16:00:25 +08:00
Redkale
9e6840f5cb 2017-05-22 15:27:53 +08:00
Redkale
52d559ea4a 2017-05-22 14:41:03 +08:00
Redkale
95a2b752af 2017-05-22 13:19:12 +08:00
Redkale
33da94960c 2017-05-22 13:05:50 +08:00
Redkale
dee2002cf3 2017-05-22 12:43:09 +08:00
Redkale
d9a318bba8 2017-05-22 09:32:14 +08:00
Redkale
05925b4f78 2017-05-21 21:21:56 +08:00
Redkale
45fe7cb3e9 2017-05-21 21:00:21 +08:00
Redkale
58271c803b 2017-05-21 20:56:57 +08:00
Redkale
88942c61b5 2017-05-21 19:31:54 +08:00
Redkale
88c4824c4f 2017-05-21 19:29:56 +08:00
Redkale
62b0be802e 2017-05-21 19:26:27 +08:00
Redkale
cdec316312 2017-05-21 18:33:39 +08:00
Redkale
8dcb999444 2017-05-21 14:18:47 +08:00
Redkale
ee460b4196 2017-05-21 14:08:55 +08:00
Redkale
d049b3f9ea 2017-05-21 13:47:31 +08:00
Redkale
c244c4edab 2017-05-21 13:19:32 +08:00
Redkale
7c533ce8d3 2017-05-21 12:52:01 +08:00
Redkale
f68686114d 2017-05-21 12:29:58 +08:00
Redkale
0859dee201 2017-05-20 13:43:02 +08:00
Redkale
46ccd83acc 2017-05-20 13:40:58 +08:00
Redkale
d5e44787c0 2017-05-20 13:15:23 +08:00
Redkale
4029b09d81 2017-05-20 13:14:00 +08:00
Redkale
e939241a8c 临时 2017-05-20 13:01:43 +08:00
Redkale
cee2c47d9a 2017-05-19 13:22:51 +08:00
Redkale
ccceaa2607 2017-05-19 13:21:09 +08:00
Redkale
358a50ecc7 2017-05-19 12:53:28 +08:00
Redkale
6aabae849d 2017-05-19 12:34:00 +08:00
Redkale
60cbd9b37d 2017-05-19 11:43:46 +08:00
Redkale
df2ee8273d 2017-05-19 11:39:10 +08:00
Redkale
8bbee0aff8 2017-05-19 11:26:21 +08:00
Redkale
01ea7f07f5 2017-05-18 16:52:44 +08:00
Redkale
ba928b389b 2017-05-18 14:22:44 +08:00
Redkale
39ba0f86f6 2017-05-17 19:10:51 +08:00
Redkale
4d523d1ca4 2017-05-17 18:35:37 +08:00
Redkale
2f60fe795c 2017-05-17 18:24:04 +08:00
Redkale
c3560b0ef0 2017-05-17 18:11:44 +08:00
Redkale
804b4dc07d 2017-05-17 18:00:15 +08:00
Redkale
bb87774ba9 临时修改 2017-05-17 02:32:36 +08:00
Redkale
f76ab977d1 2017-05-17 02:17:03 +08:00
Redkale
8003252cf3 2017-05-16 21:11:18 +08:00
Redkale
95c0d0f5cf 2017-05-16 21:09:28 +08:00
Redkale
3dcc6ea28f 2017-05-16 20:14:35 +08:00
Redkale
85c708b075 2017-05-16 20:11:45 +08:00
Redkale
278c51e26b 2017-05-16 17:13:51 +08:00
Redkale
7c0e60d191 2017-05-14 20:41:29 +08:00
Redkale
d1d10f90b9 2017-05-14 20:04:40 +08:00
Redkale
3b601979f4 2017-05-14 19:42:08 +08:00
Redkale
69cc09e76d 2017-05-14 16:05:41 +08:00
Redkale
ef28e32e04 2017-05-14 15:52:15 +08:00
Redkale
9954eaf469 2017-05-14 13:29:45 +08:00
Redkale
5ce5f53ed8 2017-05-14 13:27:07 +08:00
Redkale
8e36a7b450 2017-05-14 13:07:02 +08:00
Redkale
f15754386b 2017-05-14 12:27:27 +08:00
Redkale
6cc90ac7fe 2017-05-14 11:49:53 +08:00
Redkale
3c7f10d657 2017-05-14 11:49:31 +08:00
Redkale
21c84865b9 2017-05-14 11:47:00 +08:00
Redkale
853e823a8d 2017-05-14 11:34:15 +08:00
Redkale
6d74355fc0 2017-05-13 22:37:54 +08:00
Redkale
987914e748 2017-05-13 22:35:16 +08:00
Redkale
6e66ee0c99 2017-05-13 21:15:53 +08:00
Redkale
4f7145319f 2017-05-13 18:54:39 +08:00
Redkale
ab2656cde6 2017-05-13 18:47:03 +08:00
Redkale
27468d9f0c 2017-05-13 18:44:32 +08:00
Redkale
bb8462af2a 2017-05-13 18:17:36 +08:00
Redkale
e1df150a37 2017-05-13 16:49:21 +08:00
Redkale
bee4f31323 2017-05-13 16:40:26 +08:00
Redkale
df3a1ef84d 2017-05-13 15:39:58 +08:00
Redkale
242b13fff0 2017-05-13 15:27:34 +08:00
Redkale
c3cc9de5b5 2017-05-13 14:33:44 +08:00
Redkale
72e16b88f7 2017-05-13 14:19:23 +08:00
Redkale
f1f0227dca 2017-05-13 14:18:46 +08:00
Redkale
63fe26f9cb 2017-05-13 14:16:51 +08:00
Redkale
02fcb7b089 2017-05-13 13:56:02 +08:00
Redkale
9db9db4f5e 2017-05-13 11:23:14 +08:00
Redkale
e5ce250304 2017-05-13 11:20:18 +08:00
Redkale
a5756c0b4d 2017-05-13 10:50:52 +08:00
Redkale
0be3d8a4fa 2017-05-13 09:38:28 +08:00
Redkale
017ab1ae84 2017-05-12 22:02:19 +08:00
Redkale
c622e2437d 2017-05-12 21:46:10 +08:00
Redkale
3a1f20d438 2017-05-12 21:38:30 +08:00
Redkale
2a9b64e53e 2017-05-12 21:34:46 +08:00
Redkale
225745a282 2017-05-12 21:30:18 +08:00
Redkale
83680c46e8 2017-05-12 19:56:09 +08:00
Redkale
7484b80fb2 2017-05-12 17:57:17 +08:00
Redkale
77674ac8d2 2017-05-12 17:51:27 +08:00
Redkale
564067602f 2017-05-12 14:58:52 +08:00
Redkale
26778c58c9 2017-05-12 14:21:47 +08:00
Redkale
77cd24fa42 2017-05-12 14:19:06 +08:00
Redkale
4feea0e784 重构HttpServlet 2017-05-12 13:42:10 +08:00
Redkale
681faa415f 2017-05-12 08:09:05 +08:00
Redkale
3b54484832 改造HttpBaseServlet 的preExecute 和 authenticate 方法 2017-05-11 14:56:48 +08:00
Redkale
fa2513d934 2017-05-11 13:58:33 +08:00
Redkale
5e2be5e926 2017-05-11 13:56:36 +08:00
Redkale
4c071b0a1d 2017-05-11 13:49:52 +08:00
Redkale
9e7949d9eb 2017-05-11 13:35:09 +08:00
Redkale
29843a9812 2017-05-11 13:34:33 +08:00
Redkale
48a08f27a7 2017-05-11 13:07:37 +08:00
Redkale
4f1a0849ec 2017-05-11 12:55:40 +08:00
Redkale
6676c3fd37 REST 增加 @RestBody 特性, 获取请求内容, 参数可以是String 或 byte[] 2017-05-10 23:35:47 +08:00
Redkale
6daa45ff05 2017-05-10 17:40:56 +08:00
Redkale
28f95a89df 2017-05-03 13:41:08 +08:00
Redkale
44d11dae34 2017-05-02 08:20:54 +08:00
Redkale
a1b39ba99b 2017-05-02 08:19:32 +08:00
Redkale
abcfb8f10c 2017-05-02 08:12:19 +08:00
Redkale
33f49c7632 2017-05-02 08:10:51 +08:00
Redkale
d800a33ded 2017-05-02 08:09:01 +08:00
Redkale
f587e13bdc 2017-05-02 08:08:25 +08:00
Redkale
f9f2e080da 2017-04-30 19:25:33 +08:00
Redkale
027fa3a18b 2017-04-30 19:25:13 +08:00
Redkale
d9f50d63f0 2017-04-30 18:48:10 +08:00
Redkale
181486c348 2017-04-30 18:30:53 +08:00
Redkale
74adfdfc99 2017-04-30 17:33:15 +08:00
Redkale
c3783eb041 2017-04-30 17:08:59 +08:00
Redkale
77451561e6 2017-04-23 21:22:38 +08:00
Redkale
59d30b05f2 2017-04-23 21:08:18 +08:00
Redkale
2fcf0bb644 2017-04-23 21:03:08 +08:00
Redkale
71ab9c9728 去掉ServiceWrapper 2017-04-23 20:19:07 +08:00
Redkale
09165127e3 2017-04-23 16:47:24 +08:00
Redkale
c28310e0df 2017-04-23 16:03:24 +08:00
Redkale
51435a1c33 2017-04-23 14:19:34 +08:00
Redkale
83c70b9767 2017-04-20 22:03:07 +08:00
Redkale
5534dcd476 2017-04-20 15:03:32 +08:00
Redkale
d18a55deaf 2017-04-20 14:32:15 +08:00
Redkale
ae2d64991c 2017-04-20 14:28:59 +08:00
Redkale
ecb6b80e5e 2017-04-20 14:10:48 +08:00
Redkale
cf332fa67a 2017-04-20 14:08:13 +08:00
Redkale
ffa80c9212 2017-04-20 12:21:47 +08:00
Redkale
7463a8f6b5 2017-04-19 22:58:03 +08:00
Redkale
a168897784 2017-04-19 22:42:04 +08:00
Redkale
d39b3856ca 2017-04-19 18:52:20 +08:00
Redkale
ca9f74185b 2017-04-19 09:50:17 +08:00
Redkale
c35e421ba3 2017-04-19 07:55:45 +08:00
Redkale
65755e0787 2017-04-19 07:54:05 +08:00
Redkale
366c3becc4 2017-04-19 07:44:59 +08:00
Redkale
a1ac6ec543 2017-04-18 17:10:41 +08:00
Redkale
b27bbb7836 2017-03-31 08:11:46 +08:00
Redkale
a57574dd10 2017-03-30 23:19:54 +08:00
Redkale
a7dd22569c 2017-03-30 16:53:20 +08:00
Redkale
0bc0755fb3 2017-03-29 13:55:16 +08:00
Redkale
c2edb60218 2017-03-28 10:42:11 +08:00
Redkale
60c1a82a62 2017-03-27 10:03:55 +08:00
Redkale
e3205128b4 2017-03-27 08:23:22 +08:00
Redkale
a9dff0360f 2017-03-26 15:42:56 +08:00
Redkale
1e871cbee5 2017-03-26 15:02:54 +08:00
Redkale
41aadf33f3 2017-03-26 14:28:06 +08:00
Redkale
679567c85a 2017-03-26 14:15:36 +08:00
Redkale
b77050250c 2017-03-25 22:03:19 +08:00
Redkale
e178d1120b 2017-03-25 14:36:10 +08:00
Redkale
eca138b671 2017-03-24 11:28:01 +08:00
Redkale
0366aef672 2017-03-24 11:11:11 +08:00
Redkale
30103e5c8f 2017-03-23 14:20:35 +08:00
Redkale
cbba7701d8 2017-03-23 14:17:06 +08:00
Redkale
da53bd7db9 2017-03-23 11:20:43 +08:00
Redkale
9e7999da0f 2017-03-22 16:42:54 +08:00
Redkale
2c96f991d5 2017-03-22 16:36:09 +08:00
Redkale
67f8127452 2017-03-22 16:34:51 +08:00
Redkale
bce498885e 异步接口支持AsyncHandler子类 2017-03-22 16:05:10 +08:00
Redkale
eb57a25698 PrepareServlet.addServlet方法改为线程安全 2017-03-22 11:56:21 +08:00
Redkale
4e83e5bf71 2017-03-22 11:28:21 +08:00
Redkale
19a44ce8cf 2017-03-22 10:31:14 +08:00
Redkale
0bd0df3245 2017-03-21 17:16:28 +08:00
Redkale
4f0163736f 2017-03-21 13:09:11 +08:00
Redkale
8d03f52f09 2017-03-21 13:06:15 +08:00
Redkale
815267a590 2017-03-21 12:53:00 +08:00
Redkale
77f8d442b2 2017-03-21 12:45:41 +08:00
Redkale
aacda5d35e 2017-03-21 12:35:12 +08:00
Redkale
58d02f6471 2017-03-21 12:32:42 +08:00
Redkale
c735874cff 2017-03-21 12:02:54 +08:00
Redkale
045029b4a9 2017-03-21 11:55:57 +08:00
Redkale
f6b5882cd4 2017-03-21 11:45:40 +08:00
Redkale
63a9005e6b 2017-03-21 09:47:18 +08:00
Redkale
c4923f317b 2017-03-21 09:34:35 +08:00
Redkale
15e03c0459 2017-03-21 09:14:32 +08:00
Redkale
74f4ddf50b 2017-03-20 22:37:13 +08:00
Redkale
fdc868641d 2017-03-20 21:05:28 +08:00
Redkale
910eb88c55 2017-03-20 17:54:58 +08:00
Redkale
b597131de4 2017-03-20 17:33:32 +08:00
Redkale
56d5f97556 2017-03-20 17:08:54 +08:00
Redkale
b364dd5811 Service异步接口的返回类型强制约束为void,且必须存在对应的同步方法 2017-03-20 16:15:07 +08:00
Redkale
4fec27498c 2017-03-20 13:53:13 +08:00
Redkale
7a195ecf23 2017-03-20 13:37:40 +08:00
Redkale
95b7e819cd 2017-03-20 13:25:42 +08:00
Redkale
73d243aaf1 2017-03-20 10:59:08 +08:00
Redkale
998fecdd51 2017-03-19 21:36:16 +08:00
Redkale
b1ddc0e3a5 2017-03-18 19:21:05 +08:00
Redkale
641ff4709d 2017-03-18 19:16:06 +08:00
Redkale
13f2fbf7d6 2017-03-17 20:18:18 +08:00
Redkale
62f9882314 2017-03-17 20:08:24 +08:00
Redkale
7f270eb9d7 2017-03-17 20:04:09 +08:00
Redkale
974a6bfeaa 2017-03-17 18:18:58 +08:00
Redkale
4958b454af 2017-03-17 18:04:17 +08:00
Redkale
3531d0963d 2017-03-17 17:57:24 +08:00
Redkale
41e6497a2e 2017-03-17 16:49:55 +08:00
Redkale
3439fab690 2017-03-17 16:07:41 +08:00
Redkale
14274c8d04 2017-03-17 15:57:49 +08:00
Redkale
b3cbd9be71 2017-03-17 15:21:35 +08:00
Redkale
b1d810188c 2017-03-17 14:54:00 +08:00
Redkale
4b48f85162 2017-03-17 13:20:26 +08:00
Redkale
738b02e1b9 优化DataSource的异步接口 2017-03-17 13:09:28 +08:00
Redkale
dc487f9226 2017-03-17 12:03:42 +08:00
Redkale
bb2f43c317 2017-03-17 09:26:44 +08:00
Redkale
be61aef123 Service、DataSource、CacheSource增加异步接口 2017-03-16 20:04:20 +08:00
Redkale
6ad7888e85 2017-03-16 20:02:34 +08:00
Redkale
242adb3c9e 2017-03-16 17:46:38 +08:00
Redkale
8654c69d0c 2017-03-16 17:38:18 +08:00
Redkale
a7999ff160 2017-03-14 17:03:29 +08:00
Redkale
9c04b8aab0 2017-03-10 18:59:36 +08:00
Redkale
3643fefc9c 2017-03-09 17:22:02 +08:00
Redkale
47189901e5 2017-03-09 15:44:43 +08:00
Redkale
2577684897 2017-03-09 15:08:36 +08:00
Redkale
77396df8fd 2017-03-09 14:04:36 +08:00
Redkale
c517a1d469 增加javadoc注释 2017-03-09 11:44:12 +08:00
Redkale
b7d7e6567b 2017-03-09 11:19:13 +08:00
Redkale
67807e913e 2017-03-09 09:49:14 +08:00
Redkale
19a950dab5 2017-03-08 20:04:09 +08:00
Redkale
79b91f8386 @WebAction替换成@WebMapping 2017-03-08 18:56:07 +08:00
Redkale
0359a4b7e9 2017-03-08 17:28:33 +08:00
Redkale
d89f410749 2017-03-08 17:22:56 +08:00
Redkale
850f6dd060 2017-03-08 17:05:21 +08:00
Redkale
d891c6c8dc 2017-03-08 14:25:03 +08:00
Redkale
0a4a88ed5a 2017-03-08 14:03:05 +08:00
Redkale
3c02219da0 2017-03-08 09:57:08 +08:00
Redkale
65efc3372e 2017-03-07 17:44:50 +08:00
Redkale
3acea66788 2017-03-07 15:47:39 +08:00
Redkale
b448514e40 2017-03-07 11:58:27 +08:00
Redkale
024147344b 2017-03-07 10:09:26 +08:00
Redkale
52a34d3871 2017-03-07 09:42:03 +08:00
Redkale
1ada26e4dd 2017-03-07 09:39:16 +08:00
Redkale
94d1b61f81 2017-03-06 15:18:50 +08:00
Redkale
29299edb90 2017-03-06 14:45:35 +08:00
Redkale
a2e2c5e178 2017-03-06 12:02:00 +08:00
Redkale
8ae39df2e8 2017-03-06 09:29:25 +08:00
Redkale
508b269a82 2017-03-03 18:40:45 +08:00
Redkale
a8627b6105 2017-03-03 18:21:09 +08:00
Redkale
8fee6b2c68 2017-03-03 18:05:11 +08:00
Redkale
dd58571ffd 2017-03-03 17:50:50 +08:00
Redkale
8c25683cc5 增加javadoc注释 2017-03-03 14:49:32 +08:00
Redkale
a96f003b8c 2017-03-03 11:45:55 +08:00
Redkale
ff01443246 2017-03-02 19:59:42 +08:00
Redkale
e915a253f8 2017-03-02 16:03:29 +08:00
Redkale
b463389733 2017-03-02 15:43:34 +08:00
Redkale
41c97b92c7 删除DataSource.updateColumns方法,使用 DataSource.updateColumn代替 2017-03-02 14:21:47 +08:00
Redkale
1142f81e9c 删掉HttpResponse.finishJsResult方法 2017-03-02 14:13:29 +08:00
Redkale
5bc9f77b7b 修复HttpRequest.getBody由于URLDecode导致的BUG 2017-03-02 12:35:14 +08:00
Redkale
c5d0582807 修复HttpRequest.getBody由于URLDecode导致内容多余的BUG 2017-03-02 11:52:22 +08:00
Redkale
525e65d152 增加javadoc注释 2017-03-02 10:41:15 +08:00
Redkale
d948c7af47 增加javadoc注释 2017-03-02 10:02:45 +08:00
Redkale
11a29b4ed6 2017-03-01 20:59:00 +08:00
Redkale
e31c4a3041 DataSource增加支持Blob(byte[])类型字段功能 2017-02-28 13:37:38 +08:00
Redkale
2928d5fc93 2017-02-28 10:01:13 +08:00
Redkale
12fc6f7f10 2017-02-27 17:30:03 +08:00
Redkale
4bd8c207b4 增加javadoc注释 2017-02-27 17:15:14 +08:00
Redkale
be030a3640 增加javadoc注释 2017-02-27 17:11:23 +08:00
Redkale
ebaa250f7b 增加javadoc注释 2017-02-27 17:07:00 +08:00
Redkale
826a2d7ee6 增加javadoc注释 2017-02-27 15:06:31 +08:00
Redkale
e476cf8176 2017-02-27 13:54:23 +08:00
Redkale
03115694f9 增加javadoc注释 2017-02-27 12:01:39 +08:00
Redkale
26ffb04834 增加javadoc注释 2017-02-27 11:56:18 +08:00
Redkale
2979fcc33d 增加javadoc注释 2017-02-27 11:19:40 +08:00
217 changed files with 14080 additions and 5549 deletions

32
assembly.xml Normal file
View 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>

View File

@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<application port="5050">
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
<resources>
<!--
<properties>
@@ -8,26 +11,16 @@
</properties>
-->
</resources>
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
<!--
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<response>
<addheader name="X-Node" value="system.property.APP_NODE" />
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Credentials" value="true"/>
</response>
-->
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
<services autoload="true"/>
<servlets path="/pipes" autoload="true" >
<!--
<resource-servlet>
<caches limit="0"/>
<rewrite type="location" match="^/([^-]+)(-[^-\.]+)+\.html(.*)" forward="/$1.html"/>
</resource-servlet>
-->
</servlets>
<!-- base指定的自定义HttpServlet子类必须标记@HttpUserType, 不设置base则视为没有当前用户信息设置 -->
<rest path="/pipes" base="org.redkale.net.http.HttpServlet"/>
<servlets path="/pipes" autoload="true" />
</server>
</application>

View File

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

40
pom.xml
View File

@@ -6,7 +6,7 @@
<packaging>jar</packaging>
<url>http://redkale.org</url>
<description>redkale -- java framework</description>
<version>1.4.0-SNAPSHOT</version>
<version>1.6.2</version>
<licenses>
<license>
<name>Apache 2</name>
@@ -121,20 +121,30 @@
</goals>
</execution>
</executions>
</plugin>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>redkale</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</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>

View File

@@ -23,13 +23,14 @@
port: required 程序的管理Server的端口用于关闭或者与监管系统进行数据交互
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
-->
<application port="6560" lib="">
<application port="6560" lib="">
<!--
【节点全局唯一】
所有服务所需的资源
-->
-->
<resources>
<!--
【节点全局唯一】
transport节点只能有一个用于配置所有Transport的池参数没配置该节点将自动创建一个。
@@ -38,12 +39,13 @@
bufferPoolSize ByteBuffer池的大小默认: <group>节点数*CPU核数*8
-->
<transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/>
<!--
一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
一个group节点对应一个 Transport 对象。
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol只能是UDP TCP 默认TCP
kind: 与SNCP服务连接时的数据传输类型可选值有:rest(不区分大小写);值为空或空字符串表示按SNCP协议传输; 为rest表示按REST传输。默认值为空
protocol范围:UDP TCP 默认TCP
subprotocol: 子协议,预留字段。默认值为空
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
-->
<group name="" protocol="TCP">
@@ -57,9 +59,21 @@
-->
<node addr="127.0.0.1" port="7070"/>
</group>
<!--
全局的数据源设置, 可以是CacheSource、DataSource JDBC的DataSource通常通过persistence.xml配置此处多用于CacheSource的配置
name: 资源名,用于依赖注入。
value类名必须是CacheSource或DataSource的子类且必须实现Service接口。
groups: 指定groups。
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
-->
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
<node addr="127.0.0.1" port="7070"/>
</source>
<!--
【节点全局唯一】
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入, 被注解的字段类型只能是String、primitive class
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
load: 加载文件,多个用;隔开。
@@ -70,6 +84,8 @@
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"/>
@@ -77,10 +93,11 @@
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</properties>
</resources>
<!--
protocol: required server所启动的协议Redkale内置的有HTTP、SNCPSNCP使用TCP实现;
name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线、减号
protocol: required server所启动的协议Redkale内置的有HTTP、SNCP、WATCHSNCP使用TCP实现;
name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
host: 服务所占address 默认: 0.0.0.0
port: required 服务所占端口
root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root
@@ -90,7 +107,7 @@
backlog: 默认10K
threads 线程总数, 默认: CPU核数*16
maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 默认: 8K; 如果是HTTP协议则默认: 16K + 8B (兼容HTTP 2.0)
bufferCapacity: ByteBuffer的初始化大小 默认: 8K; 如果是HTTP协议则默认: 16K + 16B (兼容HTTP 2.0、WebSocket)
bufferPoolSize ByteBuffer池的大小默认: CPU核数*512
responsePoolSize Response池的大小默认: CPU核数*256
readTimeoutSecond: 读操作超时秒数, 默认0 表示永久不超时
@@ -128,21 +145,46 @@
</service>
</services>
<!--
加载所有的Filter服务;
autoload="true" 默认值.
autoload="false" 需要显著的指定Filter类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<filters autoload="true" includes="" excludes="">
<!-- 显著加载指定的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服务, 节点可以多个
base: REST服务的BaseServlet必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置系统会自动生成)
path: servlet的ContextPath前缀 默认为空
base: REST服务的BaseServlet必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
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="">
<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>
<!--

View File

@@ -17,7 +17,7 @@ java.util.logging.FileHandler.count = 100
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%u.log
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
#java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-error-%u.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%u.log
java.util.logging.FileHandler.append = true
#java.util.logging.ConsoleHandler.level = FINE

View File

@@ -6,6 +6,11 @@
<!-- 为NONE表示不启动缓存@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<!--
DataSource的实现类没有设置默认为org.redkale.source.DataJdbcSource的实现使用常规基于JDBC的数据库驱动一般无需设置
-->
<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的子类。

View File

@@ -15,23 +15,26 @@ import org.redkale.source.*;
import org.redkale.util.*;
/**
* 继承 HttpBaseServlet 是为了获取 WebAction 信息
* API接口文档生成类作用生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
* 继承 HttpBaseServlet 是为了获取 WebMapping 信息
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class ApiDocs extends HttpBaseServlet {
public final class ApiDocsService {
private final Application app;
private final Application app; //Application全局对象
public ApiDocs(Application app) {
public ApiDocsService(Application app) {
this.app = app;
}
public void run() throws Exception {
List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
__prefix.setAccessible(true);
Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue;
@@ -49,20 +52,20 @@ public class ApiDocs extends HttpBaseServlet {
continue;
}
final Map<String, Object> servletmap = new LinkedHashMap<>();
String prefix = _prefix(servlet);
String[] mappings = ws.value();
String prefix = (String) __prefix.get(servlet);
String[] urlregs = ws.value();
if (prefix != null && !prefix.isEmpty()) {
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix + mappings[i];
for (int i = 0; i < urlregs.length; i++) {
urlregs[i] = prefix + urlregs[i];
}
}
servletmap.put("mappings", mappings);
servletmap.put("urlregs", urlregs);
servletmap.put("moduleid", ws.moduleid());
servletmap.put("name", ws.name());
servletmap.put("comment", ws.comment());
List<Map> actionsList = new ArrayList<>();
servletmap.put("actions", actionsList);
List<Map> mappingsList = new ArrayList<>();
servletmap.put("mappings", mappingsList);
final Class selfClz = servlet.getClass();
Class clz = servlet.getClass();
HashSet<String> actionurls = new HashSet<>();
@@ -70,18 +73,18 @@ public class ApiDocs extends HttpBaseServlet {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue;
WebAction action = method.getAnnotation(WebAction.class);
HttpMapping action = method.getAnnotation(HttpMapping.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final Map<String, Object> actionmap = new LinkedHashMap<>();
final Map<String, Object> mappingmap = new LinkedHashMap<>();
if (actionurls.contains(action.url())) continue;
actionmap.put("url", prefix + action.url());
mappingmap.put("url", prefix + action.url());
actionurls.add(action.url());
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
actionmap.put("actionid", action.actionid());
actionmap.put("comment", action.comment());
mappingmap.put("auth", action.auth());
mappingmap.put("actionid", action.actionid());
mappingmap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>();
actionmap.put("params", paramsList);
mappingmap.put("params", paramsList);
List<String> results = new ArrayList<>();
for (final Class rtype : action.results()) {
results.add(rtype.getName());
@@ -110,7 +113,7 @@ public class ApiDocs extends HttpBaseServlet {
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
@@ -119,8 +122,8 @@ public class ApiDocs extends HttpBaseServlet {
} while ((loop = loop.getSuperclass()) != Object.class);
typesmap.put(rtype.getName(), typemap);
}
actionmap.put("results", results);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
mappingmap.put("results", results);
for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type();
@@ -159,7 +162,7 @@ public class ApiDocs extends HttpBaseServlet {
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
@@ -169,17 +172,17 @@ public class ApiDocs extends HttpBaseServlet {
typesmap.put(ptype.getName(), typemap);
}
actionmap.put("result", action.result());
actionsList.add(actionmap);
mappingmap.put("result", action.result());
mappingsList.add(mappingmap);
}
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletmap);
}
servletsList.sort((o1, o2) -> {
String[] mappings1 = (String[]) o1.get("mappings");
String[] mappings2 = (String[]) o2.get("mappings");
return mappings1.length > 0 ? (mappings2.length > 0 ? mappings1[0].compareTo(mappings2[0]) : 1) : -1;
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;
});
}
Map<String, Object> resultmap = new LinkedHashMap<>();
@@ -194,7 +197,7 @@ public class ApiDocs extends HttpBaseServlet {
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);
}
if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html");
if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html");
String content = Utility.read(in).replace("'${content}'", json);
in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
@@ -202,8 +205,4 @@ public class ApiDocs extends HttpBaseServlet {
outhtml.close();
}
@Override
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true;
}
}

View File

@@ -5,8 +5,9 @@
*/
package org.redkale.boot;
import org.redkale.net.TransportGroupInfo;
import java.io.*;
import java.lang.reflect.Modifier;
import java.lang.reflect.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
@@ -15,24 +16,33 @@ import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import javax.annotation.Resource;
import javax.xml.parsers.*;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.bson.BsonFactory;
import org.redkale.convert.json.JsonFactory;
import org.redkale.net.*;
import org.redkale.net.http.MimeType;
import org.redkale.net.sncp.SncpClient;
import org.redkale.net.sncp.*;
import org.redkale.service.Service;
import org.redkale.source.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.watch.WatchFactory;
import org.redkale.watch.*;
import org.w3c.dom.*;
/**
* 编译时需要加入: -XDignore.symbol.file=true
*
* 进程启动类,全局对象。 <br>
* <pre>
* 程序启动执行步骤:
* 1、读取application.xml
* 2、进行classpath扫描动态加载Service、WebSocket与Servlet
* 3、优先加载所有SNCP协议的服务再加载其他协议服务 最后加载WATCH协议的服务
* 4、最后进行Service、Servlet与其他资源之间的依赖注入
* </pre>
* <p>
* 进程启动类程序启动后读取application.xml,进行classpath扫描动态加载Service与Servlet 优先加载所有SNCP协议的服务 再加载其他协议服务, 最后进行Service、Servlet与其他资源之间的依赖注入。
* 编译时需要加入: -XDignore.symbol.file=true
* <p>
* 详情见: https://redkale.org
*
@@ -40,67 +50,94 @@ import org.w3c.dom.*;
*/
public final class Application {
//当前进程启动的时间, 类型: long
/**
* 当前进程启动的时间, 类型: long
*/
public static final String RESNAME_APP_TIME = "APP_TIME";
//当前进程的根目录, 类型String、File、Path
/**
* 当前进程的根目录, 类型String、File、Path
*/
public static final String RESNAME_APP_HOME = "APP_HOME";
//application.xml 文件中resources节点的内容 类型: AnyValue
/**
* application.xml 文件中resources节点的内容 类型: AnyValue
*/
public static final String RESNAME_APP_GRES = "APP_GRES";
//当前进程节点的name 类型String
/**
* 当前进程节点的name 类型String
*/
public static final String RESNAME_APP_NODE = "APP_NODE";
//当前进程节点的IP地址 类型InetAddress、String
/**
* 当前进程节点的IP地址 类型InetAddress、String
*/
public static final String RESNAME_APP_ADDR = "APP_ADDR";
//当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR";
/**
* 当前Service所属的SNCP Server的地址 类型: SocketAddress、InetSocketAddress、String <br>
*/
public static final String RESNAME_SNCP_ADDR = "SNCP_ADDR";
//当前SNCP Server所属的组 类型: String
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP";
/**
* 当前Service所属的SNCP Server所属的组 类型: String<br>
*/
public static final String RESNAME_SNCP_GROUP = "SNCP_GROUP";
//当前Server的ROOT目录 类型String、File、Path
/**
* "SERVER_ROOT" 当前Server的ROOT目录类型String、File、Path
*/
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
final Map<String, GroupInfo> globalGroups = new HashMap<>();
//本地IP地址
final InetAddress localAddress;
//CacheSource 资源
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
//DataSource 资源
final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
//NodeServer 资源
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
final ObjectPool<ByteBuffer> transportBufferPool;
final ExecutorService transportExecutor;
final AsynchronousChannelGroup transportChannelGroup;
//传输端的TransportFactory
final TransportFactory transportFactory;
//全局根ResourceFactory
final ResourceFactory resourceFactory = ResourceFactory.root();
//服务配置项
final AnyValue config;
//临时计数器
CountDownLatch servicecdl; //会出现两次赋值
//是否启动了WATCH协议服务
boolean watching;
//--------------------------------------------------------------------------------------------
//是否用于main方法运行
private final boolean singletonrun;
private final WatchFactory watchFactory = WatchFactory.root();
//根WatchFactory
//private final WatchFactory watchFactory = WatchFactory.root();
//进程根目录
private final File home;
//日志
private final Logger logger;
private final AnyValue config;
//服务启动时间
private final long startTime = System.currentTimeMillis();
//Server启动的计数器用于确保所有Server都启动完后再进行下一步处理
private final CountDownLatch serversLatch;
//根ClassLoader
private final NodeClassLoader classLoader;
private Application(final AnyValue config) {
this(false, config);
}
@@ -164,7 +201,8 @@ public final class Application {
Properties prop = new Properties();
final String handlers = properties.getProperty("handlers");
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", fileHandlerClass));
//singletonrun模式下不输出文件日志
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", singletonrun ? "" : fileHandlerClass));
}
if (!prop.isEmpty()) {
String prefix = fileHandlerClass + ".";
@@ -189,7 +227,7 @@ public final class Application {
}
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
logger.log(Level.INFO, "------------------------------- Redkale ------------------------------");
logger.log(Level.INFO, "------------------------------- Redkale " + Redkale.getDotedVersion() + " -------------------------------");
//------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null;
@@ -201,8 +239,8 @@ public final class Application {
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
if (transportConf != null) {
//--------------transportBufferPool-----------
AtomicLong createBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.cycleCounter");
AtomicLong createBufferCounter = new AtomicLong();
AtomicLong cycleBufferCounter = new AtomicLong();
final int bufferCapacity = transportConf.getIntValue("bufferCapacity", 8 * 1024);
final int bufferPoolSize = transportConf.getIntValue("bufferPoolSize", groupsize * Runtime.getRuntime().availableProcessors() * 8);
final int threads = transportConf.getIntValue("threads", groupsize * Runtime.getRuntime().availableProcessors() * 8);
@@ -228,17 +266,25 @@ public final class Application {
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
}
}
this.transportBufferPool = transportPool;
this.transportExecutor = transportExec;
this.transportChannelGroup = transportGroup;
this.transportFactory = new TransportFactory(transportExec, transportPool, transportGroup);
this.classLoader = new NodeClassLoader(Thread.currentThread().getContextClassLoader());
Thread.currentThread().setContextClassLoader(this.classLoader);
}
public ResourceFactory getResourceFactory() {
return resourceFactory;
}
public WatchFactory getWatchFactory() {
return watchFactory;
public TransportFactory getTransportFactory() {
return transportFactory;
}
public NodeClassLoader getNodeClassLoader() {
return classLoader;
}
public List<NodeServer> getNodeServers() {
return new ArrayList<>(servers);
}
public File getHome() {
@@ -249,10 +295,6 @@ public final class Application {
return startTime;
}
private void initLogging() {
}
public void init() throws Exception {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + Runtime.getRuntime().availableProcessors() * 4);
System.setProperty("convert.bson.tiny", "true");
@@ -264,12 +306,12 @@ public final class Application {
File persist = new File(this.home, "conf/persistence.xml");
final String homepath = this.home.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataDefaultSource.DATASOURCE_CONFPATH, persist.getCanonicalPath());
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
logger.log(Level.INFO, RESNAME_APP_HOME + "= " + homepath + "\r\n" + RESNAME_APP_ADDR + "= " + this.localAddress.getHostAddress());
String lib = config.getValue("lib", "").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
Server.loadLib(logger, lib);
initLogging();
//------------------------------------------------------------------------
final AnyValue resources = config.getAnyValue("resources");
if (resources != null) {
@@ -295,6 +337,7 @@ public final class Application {
String name = prop.getValue("name");
String value = prop.getValue("value");
if (name == null || value == null) continue;
value = value.replace("${APP_HOME}", home.getCanonicalPath()).replace('\\', '/');
if (name.startsWith("system.property.")) {
System.setProperty(name.substring("system.property.".length()), value);
} else if (name.startsWith("mimetype.property.")) {
@@ -307,15 +350,71 @@ public final class Application {
}
}
}
if (this.localAddress != null && this.resourceFactory.find("property.datasource.nodeid", String.class) == null) {
byte[] bs = this.localAddress.getAddress();
int v = (0xff & bs[bs.length - 2]) % 10 * 100 + (0xff & bs[bs.length - 1]);
this.resourceFactory.register("property.datasource.nodeid", "" + v);
}
this.resourceFactory.register(BsonFactory.root());
this.resourceFactory.register(JsonFactory.root());
this.resourceFactory.register(BsonFactory.root().getConvert());
this.resourceFactory.register(JsonFactory.root().getConvert());
//只有WatchService才能加载Application、WatchFactory
final Application application = this;
this.resourceFactory.register(new ResourceFactory.ResourceLoader() {
@Override
public void load(ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) {
try {
Resource res = field.getAnnotation(Resource.class);
if (res == null) return;
if (!(src instanceof WatchService) || Sncp.isRemote((Service) src)) return; //远程模式不得注入
Class type = field.getType();
if (type == Application.class) {
field.set(src, application);
} else if (type == TransportFactory.class) {
field.set(src, application.transportFactory);
} else if (type == NodeSncpServer.class) {
NodeServer server = null;
for (NodeServer ns : application.getNodeServers()) {
if (ns.getClass() == NodeSncpServer.class) continue;
if (res.name().equals(ns.server.getName())) {
server = ns;
break;
}
}
field.set(src, server);
} else if (type == NodeHttpServer.class) {
NodeServer server = null;
for (NodeServer ns : application.getNodeServers()) {
if (ns.getClass() == NodeHttpServer.class) continue;
if (res.name().equals(ns.server.getName())) {
server = ns;
break;
}
}
field.set(src, server);
} else if (type == NodeWatchServer.class) {
NodeServer server = null;
for (NodeServer ns : application.getNodeServers()) {
if (ns.getClass() == NodeWatchServer.class) continue;
if (res.name().equals(ns.server.getName())) {
server = ns;
break;
}
}
field.set(src, server);
}
// if (type == WatchFactory.class) {
// field.set(src, application.watchFactory);
// }
} catch (Exception e) {
logger.log(Level.SEVERE, "Resource inject error", e);
}
}
@Override
public boolean autoNone() {
return false;
}
}, Application.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
//--------------------------------------------------------------------------
initResources();
}
@@ -324,25 +423,18 @@ public final class Application {
final AnyValue resources = config.getAnyValue("resources");
if (resources != null) {
//------------------------------------------------------------------------
for (AnyValue conf : resources.getAnyValues("group")) {
final String group = conf.getValue("name", "");
final String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase();
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
}
GroupInfo ginfo = globalGroups.get(group);
if (ginfo == null) {
ginfo = new GroupInfo(group, protocol, conf.getValue("kind", ""), new LinkedHashSet<>());
globalGroups.put(group, ginfo);
}
TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, conf.getValue("subprotocol", ""), new LinkedHashSet<>());
for (AnyValue node : conf.getAnyValues("node")) {
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
ginfo.addrs.add(addr);
String oldgroup = globalNodes.get(addr);
if (oldgroup != null) throw new RuntimeException(addr + " had one more group " + (globalNodes.get(addr)));
globalNodes.put(addr, group);
ginfo.putAddress(addr);
}
transportFactory.addGroupInfo(ginfo);
}
}
//------------------------------------------------------------------------
@@ -392,7 +484,7 @@ public final class Application {
}
} else if ("APIDOC".equalsIgnoreCase(new String(bytes))) {
try {
new ApiDocs(application).run();
new ApiDocsService(application).run();
buffer.clear();
buffer.put("APIDOC OK".getBytes());
buffer.flip();
@@ -423,13 +515,27 @@ public final class Application {
channel.write(buffer);
buffer.clear();
channel.configureBlocking(false);
channel.read(buffer);
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
channel.close();
logger.info(new String(bytes));
Thread.sleep(500);
try {
channel.read(buffer);
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
channel.close();
logger.info(new String(bytes));
Thread.sleep(500);
} catch (Exception e) {
if (e instanceof PortUnreachableException) {
if ("APIDOC".equalsIgnoreCase(command)) {
final Application application = Application.create(true);
application.init();
application.start();
new ApiDocsService(application).run();
logger.info("APIDOC OK");
return;
}
}
throw e;
}
}
public void start() throws Exception {
@@ -437,20 +543,25 @@ public final class Application {
CountDownLatch timecd = new CountDownLatch(entrys.length);
final List<AnyValue> sncps = new ArrayList<>();
final List<AnyValue> others = new ArrayList<>();
final List<AnyValue> watchs = new ArrayList<>();
for (final AnyValue entry : entrys) {
if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) {
sncps.add(entry);
} else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) {
watchs.add(entry);
} else {
others.add(entry);
}
}
this.watching = !watchs.isEmpty();
//单向SNCP服务不需要对等group
//if (!sncps.isEmpty() && globalNodes.isEmpty()) throw new RuntimeException("found SNCP Server node but not found <group> node info.");
runServers(timecd, sncps); //必须确保sncp都启动后再启动其他协议
runServers(timecd, others);
runServers(timecd, watchs); //必须在所有server都启动后再启动
timecd.await();
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms");
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n");
if (!singletonrun) this.serversLatch.await();
}
@@ -477,13 +588,22 @@ public final class Application {
NodeServer server = null;
if ("SNCP".equals(protocol)) {
server = NodeSncpServer.createNodeServer(Application.this, serconf);
} else if ("WATCH".equalsIgnoreCase(protocol)) {
DefaultAnyValue serconf2 = (DefaultAnyValue) serconf;
DefaultAnyValue rest = (DefaultAnyValue) serconf2.getAnyValue("rest");
if (rest == null) {
rest = new DefaultAnyValue();
serconf2.addValue("rest", rest);
}
rest.setValue("base", WatchServlet.class.getName());
server = new NodeWatchServer(Application.this, serconf);
} else if ("HTTP".equalsIgnoreCase(protocol)) {
server = new NodeHttpServer(Application.this, serconf);
} else {
if (!inited.get()) {
synchronized (nodeClasses) {
if (!inited.getAndSet(true)) { //加载自定义的协议SOCKS
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class);
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class, (Class[]) null);
ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter);
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
for (FilterEntry<NodeServer> entry : entrys) {
@@ -493,7 +613,9 @@ public final class Application {
p = p.toUpperCase();
if ("SNCP".equals(p) || "HTTP".equals(p)) continue;
final Class<? extends NodeServer> old = nodeClasses.get(p);
if (old != null && old != type) throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
if (old != null && old != type) {
throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
}
nodeClasses.put(p, type);
}
}
@@ -570,17 +692,6 @@ public final class Application {
System.exit(0);
}
Set<String> findSncpGroups(Transport sameGroupTransport, Collection<Transport> diffGroupTransports) {
Set<String> gs = new HashSet<>();
if (sameGroupTransport != null) gs.add(sameGroupTransport.getName());
if (diffGroupTransports != null) {
for (Transport t : diffGroupTransports) {
gs.add(t.getName());
}
}
return gs;
}
NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) {
for (NodeServer node : servers) {
if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) {
@@ -590,11 +701,6 @@ public final class Application {
return null;
}
GroupInfo findGroupInfo(String group) {
if (group == null) return null;
return globalGroups.get(group);
}
private void shutdown() throws Exception {
servers.stream().forEach((server) -> {
try {
@@ -607,26 +713,22 @@ public final class Application {
});
for (DataSource source : dataSources) {
if (source == null) continue;
try {
source.getClass().getMethod("close").invoke(source);
} catch (Exception e) {
logger.log(Level.FINER, "close DataSource erroneous", e);
logger.log(Level.FINER, source.getClass() + " close DataSource erroneous", e);
}
}
for (CacheSource source : cacheSources) {
if (source == null) continue;
try {
source.getClass().getMethod("close").invoke(source);
} catch (Exception e) {
logger.log(Level.FINER, "close CacheSource erroneous", e);
}
}
if (this.transportChannelGroup != null) {
try {
this.transportChannelGroup.shutdownNow();
} catch (Exception e) {
logger.log(Level.FINER, "close transportChannelGroup erroneous", e);
logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e);
}
}
this.transportFactory.shutdownNow();
}
private static AnyValue load(final InputStream in0) {

View File

@@ -28,9 +28,9 @@ import org.redkale.util.AnyValue.DefaultAnyValue;
@SuppressWarnings("unchecked")
public final class ClassFilter<T> {
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName());
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
private static final boolean finer = logger.isLoggable(Level.FINER);
private static final boolean finer = logger.isLoggable(Level.FINER); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
@@ -40,6 +40,8 @@ public final class ClassFilter<T> {
private Class superClass; //符合的父类型。不为空时扫描结果的class必须是superClass的子类
private Class[] excludeSuperClasses; //不符合的父类型。
private Class<? extends Annotation> annotationClass;//符合的注解。不为空时扫描结果的class必须包含该注解
private Pattern[] includePatterns; //符合的classname正则表达式
@@ -56,18 +58,19 @@ public final class ClassFilter<T> {
private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass) {
this(annotationClass, superClass, null);
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses) {
this(annotationClass, superClass, excludeSuperClasses, null);
}
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, AnyValue conf) {
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) {
this.annotationClass = annotationClass;
this.superClass = superClass;
this.excludeSuperClasses = excludeSuperClasses;
this.conf = conf;
}
public static ClassFilter create(String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
ClassFilter filter = new ClassFilter(null, null);
public static ClassFilter create(Class[] excludeSuperClasses, String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
ClassFilter filter = new ClassFilter(null, null, excludeSuperClasses);
filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";"));
filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";"));
filter.setPrivilegeIncludes(includeValues);
@@ -247,7 +250,13 @@ public final class ClassFilter<T> {
public boolean accept(AnyValue property, Class clazz, boolean autoscan) {
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) 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) {
@@ -269,6 +278,18 @@ public final class ClassFilter<T> {
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) {
this.annotationClass = annotationClass;
}
@@ -293,10 +314,6 @@ public final class ClassFilter<T> {
return annotationClass;
}
public Class getSuperClass() {
return superClass;
}
public boolean isRefused() {
return refused;
}

View File

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

View File

@@ -0,0 +1,28 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot;
import java.net.*;
/**
*
* @author zhangjx
*/
public class NodeClassLoader extends URLClassLoader {
public NodeClassLoader(ClassLoader parent) {
super(new URL[0], parent);
}
public Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
@Override
public void addURL(URL url) {
super.addURL(url);
}
}

View File

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

View File

@@ -5,10 +5,8 @@
*/
package org.redkale.boot;
import java.util.Objects;
import org.redkale.service.Service;
/**
* NodeServer的拦截类
*
* <p>
* 详情见: https://redkale.org
@@ -17,71 +15,24 @@ import org.redkale.service.Service;
*/
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) {
}
public static class InterceptorServiceWrapper<T extends Service> {
private String name;
private Class<T> type;
private T service;
public InterceptorServiceWrapper() {
}
public InterceptorServiceWrapper(String name, Class<T> type, T service) {
this.name = name;
this.type = type;
this.service = service;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class<T> getType() {
return type;
}
public void setType(Class<T> type) {
this.type = type;
}
public T getService() {
return service;
}
public void setService(T service) {
this.service = service;
}
@Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + Objects.hashCode(this.name);
hash = 97 * hash + Objects.hashCode(this.type);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final InterceptorServiceWrapper<?> other = (InterceptorServiceWrapper<?>) obj;
return Objects.equals(this.name, other.name) && Objects.equals(this.type, other.type);
}
}
}

View File

@@ -8,7 +8,7 @@ package org.redkale.boot;
import java.lang.annotation.*;
/**
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑, 只能注解在NodeServer子类上
*
* <p>
* 详情见: https://redkale.org

View File

@@ -8,24 +8,24 @@ package org.redkale.boot;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.logging.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.persistence.Transient;
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.WebSocketNode;
import org.redkale.net.http.WebSocketServlet;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
/**
* Server节点的初始化配置类
@@ -44,15 +44,6 @@ public abstract class NodeServer {
//日志输出对象
protected final Logger logger;
//日志是否为FINE级别
protected final boolean fine;
//日志是否为FINER级别
protected final boolean finer;
//日志是否为FINEST级别
protected final boolean finest;
//进程主类
protected final Application application;
@@ -62,14 +53,17 @@ public abstract class NodeServer {
//当前Server对象
protected final Server server;
//ClassLoader
protected final NodeClassLoader classLoader;
//当前Server的SNCP协议的组
private String sncpGroup = null;
protected String sncpGroup = null;
//SNCP服务的地址 非SNCP为null
private InetSocketAddress sncpAddress;
//加载Service时的处理函数
protected Consumer<ServiceWrapper> consumer;
protected Consumer<Service> consumer;
//server节点的配置
protected AnyValue serverConf;
@@ -78,22 +72,25 @@ public abstract class NodeServer {
protected NodeInterceptor interceptor;
//供interceptor使用的Service对象集合
protected final Set<NodeInterceptor.InterceptorServiceWrapper> interceptorServiceWrappers = new LinkedHashSet<>();
protected final Set<Service> interceptorServices = new LinkedHashSet<>();
//本地模式的Service对象集合
protected final Set<ServiceWrapper> localServiceWrappers = new LinkedHashSet<>();
protected final Set<Service> localServices = new LinkedHashSet<>();
//远程模式的Service对象集合
protected final Set<ServiceWrapper> remoteServiceWrappers = new LinkedHashSet<>();
protected final Set<Service> remoteServices = new LinkedHashSet<>();
private volatile int maxClassNameLength = 0;
private volatile int maxNameLength = 0;
public NodeServer(Application application, Server server) {
this.application = application;
this.resourceFactory = application.getResourceFactory().createChild();
this.server = server;
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.fine = logger.isLoggable(Level.FINE);
this.finer = logger.isLoggable(Level.FINER);
this.finest = logger.isLoggable(Level.FINEST);
this.classLoader = new NodeClassLoader(Thread.currentThread().getContextClassLoader());
Thread.currentThread().setContextClassLoader(this.classLoader);
}
protected Consumer<Runnable> getExecutor() throws Exception {
@@ -116,7 +113,7 @@ public abstract class NodeServer {
if (context == null) {
t.run();
} else {
context.submit(t);
context.submitAsync(t);
}
}
@@ -136,13 +133,17 @@ public abstract class NodeServer {
if (isSNCP()) { // SNCP协议
String host = this.serverConf.getValue("host", "0.0.0.0").replace("0.0.0.0", "");
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
this.sncpGroup = application.globalNodes.get(this.sncpAddress);
this.sncpGroup = application.transportFactory.findGroupName(this.sncpAddress);
//单向SNCP服务不需要对等group
//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_SERVER_ADDR, this.sncpAddress);
if (this.sncpGroup != null) this.resourceFactory.register(RESNAME_SERVER_GROUP, this.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");
@@ -165,155 +166,216 @@ public abstract class NodeServer {
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
String interceptorClass = this.serverConf.getValue("interceptor", "");
if (!interceptorClass.isEmpty()) {
Class clazz = Class.forName(interceptorClass);
Class clazz = Class.forName(interceptorClass);
this.interceptor = (NodeInterceptor) clazz.newInstance();
}
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter<Service> serviceFilter = createServiceClassFilter();
ClassFilter<Filter> filterFilter = createFilterClassFilter();
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter otherFilter = createOtherClassFilter();
long s = System.currentTimeMillis();
if (servletFilter == null) {
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter);
} else {
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter, servletFilter);
}
ClassFilter.Loader.load(application.getHome(), 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); //必须在servlet之前
loadServlet(servletFilter);
loadService(serviceFilter, otherFilter); //必须在servlet之前
loadFilter(filterFilter, otherFilter);
loadServlet(servletFilter, otherFilter);
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
}
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception;
protected abstract void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception;
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception;
private void initResource() {
final NodeServer self = this;
//---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory();
final TransportFactory appTranFactory = application.getTransportFactory();
final AnyValue resources = application.config.getAnyValue("resources");
final Map<String, AnyValue> cacheResource = new HashMap<>();
//final Map<String, AnyValue> dataResources = new HashMap<>();
if (resources != null) {
for (AnyValue sourceConf : resources.getAnyValues("source")) {
try {
Class type = Class.forName(sourceConf.getValue("value"));
if (!Service.class.isAssignableFrom(type)) {
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
} else if (CacheSource.class.isAssignableFrom(type)) {
cacheResource.put(sourceConf.getValue("name", ""), sourceConf);
} else if (DataSource.class.isAssignableFrom(type)) {
//dataResources.put(sourceConf.getValue("name", ""), sourceConf);
//暂时不支持DataSource通过<resources>设置
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
} else {
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "load application source resource error: " + sourceConf, e);
}
}
}
//------------------------------------- 注册Resource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
Resource res = field.getAnnotation(Resource.class);
if (res == null || !res.name().startsWith("properties.")) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
Class type = field.getType();
if (type != AnyValue.class && type != AnyValue[].class) return;
Object resource = null;
final AnyValue properties = resources == null ? null : resources.getAnyValue("properties");
if (properties != null && type == AnyValue.class) {
resource = properties.getAnyValue(res.name().substring("properties.".length()));
appResFactory.register(resourceName, AnyValue.class, resource);
} else if (properties != null && type == AnyValue[].class) {
resource = properties.getAnyValues(res.name().substring("properties.".length()));
appResFactory.register(resourceName, AnyValue[].class, resource);
}
field.set(src, resource);
} catch (Exception e) {
logger.log(Level.SEVERE, "Resource inject error", e);
}
}, AnyValue.class, AnyValue[].class);
//------------------------------------- 注册DataSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
DataSource source = new DataDefaultSource(resourceName);
DataSource source = DataSources.createDataSource(resourceName);
application.dataSources.add(source);
appResFactory.register(resourceName, DataSource.class, source);
SncpClient client = Sncp.getSncpClient((Service) src);
Transport sameGroupTransport = Sncp.getSameGroupTransport((Service) src);
List<Transport> diffGroupTransports = Arrays.asList(Sncp.getDiffGroupTransports((Service) src));
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, DataCacheListenerService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpServer.getSncpGroup(), gs, null);
localServiceWrappers.add(wrapper);
sncpServer.consumerAccept(wrapper);
final Set<String> groups = new HashSet<>();
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
Service cacheListenerService = Sncp.createLocalService(resourceName, DataCacheListenerService.class, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf((Service) src));
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
localServices.add(cacheListenerService);
sncpServer.consumerAccept(cacheListenerService);
rf.inject(cacheListenerService, self);
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + cacheListenerService);
}
field.set(src, source);
rf.inject(source, self); // 给 "datasource.nodeid" 赋值;
rf.inject(source, self); // 给其可能包含@Resource的字段赋值;
//NodeServer.this.watchFactory.inject(src);
if (source instanceof Service) ((Service) source).init(null);
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
}, DataSource.class);
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 CacheSource
SncpClient client = Sncp.getSncpClient((Service) src);
Transport sameGroupTransport = Sncp.getSameGroupTransport((Service) src);
Transport[] dts = Sncp.getDiffGroupTransports((Service) src);
List<Transport> diffGroupTransports = dts == null ? new ArrayList<>() : Arrays.asList(dts);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheSourceService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
source.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class);
if (field.getAnnotation(Transient.class) != null) source.setNeedStore(false); //必须在setStoreType之后
application.cacheSources.add(source);
appResFactory.register(resourceName, genericType, source);
appResFactory.register(resourceName, CacheSource.class, source);
field.set(src, source);
rf.inject(source, self); //
((Service) source).init(null);
//------------------------------------- 注册CacheSource --------------------------------------------------------
resourceFactory.register(new ResourceFactory.ResourceLoader() {
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; //远程模式不需要注入 CacheSource
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient(srcService);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final AnyValue sourceConf = cacheResource.get(resourceName);
final Class sourceType = sourceConf == null ? CacheMemorySource.class : Class.forName(sourceConf.getValue("type"));
final Set<String> groups = new HashSet<>();
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
final CacheSource source = (CacheSource) Sncp.createLocalService(resourceName, sourceType, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
if (sourceType == CacheMemorySource.class) {
CacheMemorySource memorySource = (CacheMemorySource) source;
memorySource.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class);
if (field.getAnnotation(Transient.class) != null) memorySource.setNeedStore(false); //必须在setStoreType之后
}
application.cacheSources.add(source);
appResFactory.register(resourceName, genericType, source);
appResFactory.register(resourceName, CacheSource.class, source);
field.set(src, source);
rf.inject(source, self); //
if (source instanceof Service) ((Service) source).init(sourceConf);
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheSourceService
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, sncpServer.getSncpGroup(), gs, null);
sncpServer.getSncpServer().addSncpServlet(wrapper);
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
sncpServer.getSncpServer().addSncpServlet((Service) source);
//logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
}
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
public boolean autoNone() {
return false;
}
}, CacheSource.class);
}
@SuppressWarnings("unchecked")
protected void loadService(ClassFilter serviceFilter) throws Exception {
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
if (serviceFilter == null) return;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
final Set<FilterEntry<Service>> entrys = serviceFilter.getAllFilterEntrys();
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
for (FilterEntry<Service> entry : entrys) { //service实现类
final Class<? extends Service> type = entry.getType();
if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过
if (!Modifier.isPublic(type.getModifiers())) continue;
final ResourceFactory appResourceFactory = application.getResourceFactory();
final TransportFactory appTransportFactory = application.getTransportFactory();
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 (entry.isExpect()) {
if (Modifier.isAbstract(type.getModifiers())) continue; //修饰abstract的类跳过
if (DataSource.class.isAssignableFrom(type)) continue;
if (CacheSource.class.isAssignableFrom(type)) continue;
if (DataCacheListener.class.isAssignableFrom(type)) continue;
if (WebSocketNode.class.isAssignableFrom(type)) continue;
if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
if (DataCacheListener.class.isAssignableFrom(serviceImplClass)) continue;
//if (WebSocketNode.class.isAssignableFrom(serviceImplClass)) continue;
}
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
if (resourceFactory.find(entry.getName(), type) != null) { //Server加载Service时需要判断是否已经加载过了。
Service oldother = resourceFactory.find(entry.getName(), type);
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother));
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
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() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) //非SNCP的Server通常是单点服务
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !serviceImplClass.isInterface() && !Modifier.isAbstract(serviceImplClass.getModifiers())) //非SNCP的Server通常是单点服务
|| groups.contains(this.sncpGroup) //本地IP含在内的
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|| type.getAnnotation(LocalService.class) != null;//本地模式
if (localed && (type.isInterface() || Modifier.isAbstract(type.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final BiConsumer<ResourceFactory, Boolean> runner = (ResourceFactory rf, Boolean needinject) -> {
|| 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 {
Service service;
if (localed) { //本地模式
service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type,
NodeServer.this.sncpAddress, loadTransport(NodeServer.this.sncpGroup), loadTransports(groups));
boolean ws = src instanceof WebSocketServlet;
if (ws || localed) { //本地模式
service = Sncp.createLocalService(resourceName, serviceImplClass, appResourceFactory, appTransportFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
} else {
service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, NodeServer.this.sncpAddress, loadTransport(groups));
service = Sncp.createRemoteService(resourceName, serviceImplClass, appTransportFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
}
if (SncpClient.parseMethod(type).isEmpty()) return; //class没有可用的方法 通常为BaseService
final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty());
for (final Class restype : wrapper.getTypes()) {
if (resourceFactory.find(wrapper.getName(), restype) == null) {
regFactory.register(wrapper.getName(), restype, wrapper.getService());
if (needinject) rf.inject(wrapper.getService()); //动态加载的Service也存在按需加载的注入资源
} else if (isSNCP() && !entry.isAutoload()) {
throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat.");
}
if (SncpClient.parseMethod(serviceImplClass).isEmpty()) return; //class没有可用的方法 通常为BaseService
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 (wrapper.isRemote()) {
remoteServiceWrappers.add(wrapper);
if (Sncp.isRemote(service)) {
remoteServices.add(service);
} else {
localServiceWrappers.add(wrapper);
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, service));
if (consumer != null) consumer.accept(wrapper);
if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
localServices.add(service);
interceptorServices.add(service);
if (consumer != null) consumer.accept(service);
}
} catch (RuntimeException ex) {
throw ex;
@@ -322,14 +384,10 @@ public abstract class NodeServer {
}
};
if (entry.isExpect()) {
ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
runner.accept(rf, true);
};
for (final Class restype : ServiceWrapper.parseTypes(entry.getType())) {
resourceFactory.register(resourceLoader, restype);
}
ResourceType rty = entry.getType().getAnnotation(ResourceType.class);
resourceFactory.register(resourceLoader, rty == null ? entry.getType() : rty.value());
} else {
runner.accept(resourceFactory, false);
resourceLoader.load(resourceFactory, null, entry.getName(), null, false);
}
}
@@ -339,30 +397,38 @@ public abstract class NodeServer {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
//---------------- inject ----------------
new ArrayList<>(localServiceWrappers).forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this);
new ArrayList<>(localServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this);
calcMaxLength(y);
});
new ArrayList<>(remoteServiceWrappers).forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this);
new ArrayList<>(remoteServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this);
calcMaxLength(y);
});
if (sb != null) {
remoteServiceWrappers.forEach(y -> {
sb.append(threadName).append(y.toSimpleString()).append(" load and inject").append(LINE_SEPARATOR);
remoteServices.forEach(y -> {
sb.append(threadName).append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" load and inject").append(LINE_SEPARATOR);
});
}
//----------------- init -----------------
List<ServiceWrapper> swlist = new ArrayList<>(localServiceWrappers);
Collections.sort(swlist);
localServiceWrappers.clear();
localServiceWrappers.addAll(swlist);
List<Service> swlist = new ArrayList<>(localServices);
Collections.sort(swlist, (o1, o2) -> {
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);
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
CountDownLatch clds = new CountDownLatch(localServiceWrappers.size());
localServiceWrappers.parallelStream().forEach(y -> {
CountDownLatch clds = new CountDownLatch(localServices.size());
localServices.parallelStream().forEach(y -> {
try {
long s = System.currentTimeMillis();
y.getService().init(y.getConf());
y.init(Sncp.getConf(y));
long e = System.currentTimeMillis() - s;
if (slist != null) slist.add(new StringBuilder().append(threadName).append(y.toSimpleString()).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
} finally {
clds.countDown();
}
@@ -378,76 +444,95 @@ public abstract class NodeServer {
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
protected List<Transport> loadTransports(final HashSet<String> groups) {
if (groups == null) return null;
final List<Transport> transports = new ArrayList<>();
for (String group : groups) {
if (this.sncpGroup == null || !this.sncpGroup.equals(group)) {
transports.add(loadTransport(group));
}
}
return transports;
private void calcMaxLength(Service y) { //计算toString中的长度
maxNameLength = Math.max(maxNameLength, Sncp.getResourceName(y).length());
maxClassNameLength = Math.max(maxClassNameLength, Sncp.getResourceType(y).getName().length() + 1);
}
protected Transport loadTransport(final HashSet<String> groups) {
if (groups == null || groups.isEmpty()) return null;
final String groupid = new ArrayList<>(groups).stream().sorted().collect(Collectors.joining(";")); //按字母排列顺序
Transport transport = application.resourceFactory.find(groupid, Transport.class);
if (transport != null) return transport;
final List<Transport> transports = new ArrayList<>();
for (String group : groups) {
transports.add(loadTransport(group));
}
Set<InetSocketAddress> addrs = new HashSet();
transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses())));
Transport first = transports.get(0);
GroupInfo ginfo = application.findGroupInfo(first.getName());
Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
synchronized (application.resourceFactory) {
transport = application.resourceFactory.find(groupid, Transport.class);
if (transport == null) {
transport = newTransport;
application.resourceFactory.register(groupid, transport);
}
}
return transport;
}
protected Transport loadTransport(final String group) {
if (group == null) return null;
Transport transport;
synchronized (application.resourceFactory) {
transport = application.resourceFactory.find(group, Transport.class);
if (transport != null) {
if (this.sncpAddress != null && !this.sncpAddress.equals(transport.getClientAddress())) {
throw new RuntimeException(transport + "repeat create on newClientAddress = " + this.sncpAddress + ", oldClientAddress = " + transport.getClientAddress());
}
return transport;
}
GroupInfo ginfo = application.findGroupInfo(group);
Set<InetSocketAddress> addrs = ginfo.copyAddrs();
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
application.resourceFactory.register(group, transport);
}
return transport;
}
/*
* protected List<Transport> loadTransports(final HashSet<String> groups) {
* if (groups == null) return null;
* final List<Transport> transports = new ArrayList<>();
* for (String group : groups) {
* if (this.sncpGroup == null || !this.sncpGroup.equals(group)) {
* transports.add(loadTransport(group));
* }
* }
* return transports;
* }
* protected Transport loadTransport(final HashSet<String> groups) {
* if (groups == null || groups.isEmpty()) return null;
* final String groupid = new ArrayList<>(groups).stream().sorted().collect(Collectors.joining(";")); //按字母排列顺序
* Transport transport = application.resourceFactory.find(groupid, Transport.class);
* if (transport != null) return transport;
* final List<Transport> transports = new ArrayList<>();
* for (String group : groups) {
* transports.add(loadTransport(group));
* }
* Set<InetSocketAddress> addrs = new HashSet();
* transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses())));
* Transport first = transports.get(0);
* TransportGroupInfo ginfo = application.transportFactory.findGroupInfo(first.getName());
* Transport newTransport = new Transport(groupid, ginfo.getProtocol(),
* ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
* synchronized (application.resourceFactory) {
* transport = application.resourceFactory.find(groupid, Transport.class);
* if (transport == null) {
* transport = newTransport;
* application.resourceFactory.register(groupid, transport);
* }
* }
* return transport;
* }
*
* protected Transport loadTransport(final String group) {
* if (group == null) return null;
* Transport transport;
* synchronized (application.resourceFactory) {
* transport = application.resourceFactory.find(group, Transport.class);
* if (transport != null) {
* if (this.sncpAddress != null && !this.sncpAddress.equals(transport.getClientAddress())) {
* throw new RuntimeException(transport + "repeat create on newClientAddress = " + this.sncpAddress + ", oldClientAddress = " + transport.getClientAddress());
* }
* return transport;
* }
* TransportGroupInfo ginfo = application.findGroupInfo(group);
* Set<InetSocketAddress> addrs = ginfo.copyAddresses();
* if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
* transport = new Transport(group, ginfo.getProtocol(), ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
* application.resourceFactory.register(group, transport);
* }
* return transport;
* }
*/
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, Annotation.class, "services", "service");
return createClassFilter(this.sncpGroup, null, Service.class, (!isSNCP() || application.watching) ? null : new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
}
protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref,
Class inter, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(ref, inter, null);
if (properties == null && properties == null) return cf;
if (this.serverConf == null) return cf;
Class inter, Class[] excludeSuperClasses, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(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) return cf;
if (proplist == null || proplist.length < 1) {
cf.setRefused(true);
return cf;
}
cf = null;
for (AnyValue list : proplist) {
DefaultAnyValue prop = null;
@@ -461,20 +546,20 @@ public abstract class NodeServer {
prop = new AnyValue.DefaultAnyValue();
prop.addValue("groups", sc);
}
ClassFilter filter = new ClassFilter(ref, inter, prop);
for (AnyValue av : list.getAnyValues(property)) { // <service><servlet> 节点
ClassFilter filter = new ClassFilter(ref, inter, excludeSuperClasses, prop);
for (AnyValue av : list.getAnyValues(property)) { // <service>、<filter>、<servlet> 节点
final AnyValue[] items = av.getAnyValues("property");
if (av instanceof DefaultAnyValue && items.length > 0) { //存在 <property>节点
DefaultAnyValue dav = DefaultAnyValue.create();
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
if (strings != null) { //将<service><servlet>节点的属性值传给dav
if (strings != null) { //将<service>、<filter>、<servlet>节点的属性值传给dav
for (AnyValue.Entry<String> en : strings) {
dav.addValue(en.name, en.getValue());
}
}
final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys();
if (anys != null) {
for (AnyValue.Entry<AnyValue> en : anys) { //将<service><servlet>节点的非property属性节点传给dav
for (AnyValue.Entry<AnyValue> en : anys) { //将<service>、<filter>、<servlet>节点的非property属性节点传给dav
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
}
}
@@ -508,6 +593,14 @@ public abstract class NodeServer {
return false;
}
public ResourceFactory getResourceFactory() {
return resourceFactory;
}
public NodeClassLoader getNodeClassLoader() {
return classLoader;
}
public InetSocketAddress getSncpAddress() {
return sncpAddress;
}
@@ -532,12 +625,12 @@ public abstract class NodeServer {
public void shutdown() throws IOException {
if (interceptor != null) interceptor.preShutdown(this);
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
localServiceWrappers.forEach(y -> {
localServices.forEach(y -> {
long s = System.currentTimeMillis();
y.getService().destroy(y.getConf());
y.destroy(Sncp.getConf(y));
long e = System.currentTimeMillis() - s;
if (e > 2 && sb != null) {
sb.append(y.toSimpleString()).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
sb.append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
}
});
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
@@ -548,16 +641,16 @@ public abstract class NodeServer {
return (T) server;
}
public Set<NodeInterceptor.InterceptorServiceWrapper> getInterceptorServiceWrappers() {
return new LinkedHashSet<>(interceptorServiceWrappers);
public Set<Service> getInterceptorServices() {
return new LinkedHashSet<>(interceptorServices);
}
public Set<ServiceWrapper> getLocalServiceWrappers() {
return new LinkedHashSet<>(localServiceWrappers);
public Set<Service> getLocalServices() {
return new LinkedHashSet<>(localServices);
}
public Set<ServiceWrapper> getRemoteServiceWrappers() {
return new LinkedHashSet<>(remoteServiceWrappers);
public Set<Service> getRemoteServices() {
return new LinkedHashSet<>(remoteServices);
}
}

View File

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

View File

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

View File

@@ -36,8 +36,8 @@
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>');
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
for (var k = 0; k < servlet.actions.length; k++) {
var action = servlet.actions[k];
for (var k = 0; k < servlet.mappings.length; k++) {
var action = servlet.mappings[k];
html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>');

View File

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

View File

@@ -8,9 +8,9 @@ package org.redkale.convert;
import java.lang.reflect.*;
/**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组.
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有必要采用int存储。
* 支持一定程度的泛型。
* 数组的序列化操作类 <br>
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 <br>
*
* <p>
* 详情见: https://redkale.org

View File

@@ -11,9 +11,8 @@ import java.lang.reflect.Type;
import java.util.Collection;
/**
* 对象集合的反序列化.
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。
* 支持一定程度的泛型。
* Collection的反序列化操作类 <br>
* 支持一定程度的泛型。 <br>
*
* <p>
* 详情见: https://redkale.org
@@ -45,6 +44,11 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else if(factory.isReversible()){
this.componentType = Object.class;
this.creator = factory.loadCreator(Object.class);
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
}

View File

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

View File

@@ -6,7 +6,7 @@
package org.redkale.convert;
/**
* 序列化操作类
* 序列化/反序列化操作类
*
* <p>
* 详情见: https://redkale.org

View File

@@ -10,11 +10,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* 用于类名的别名 类似javax.persistence.Table
* 该值必须是全局唯一
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。
* 用于类名的别名, 该值必须是全局唯一 <br>
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.writeClassName(String value) 。
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
@Inherited
@@ -23,5 +24,10 @@ import java.lang.annotation.*;
@Retention(RUNTIME)
public @interface ConvertEntity {
/**
* 别名值
*
* @return String
*/
String value();
}

View File

@@ -5,8 +5,11 @@
package org.redkale.convert;
/**
* 序列化自定义异常类
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public class ConvertException extends RuntimeException {

View File

@@ -5,18 +5,22 @@
*/
package org.redkale.convert;
import java.io.File;
import java.lang.reflect.*;
import java.math.BigInteger;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.redkale.convert.ext.InetAddressSimpledCoder.InetSocketAddressSimpledCoder;
import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
* 序列化模块的工厂类用于注册自定义的序列化类型获取Convert
*
* <p>
* 详情见: https://redkale.org
@@ -90,10 +94,13 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(Class.class, TypeSimpledCoder.instance);
this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance);
this.register(Pattern.class, PatternSimpledCoder.instance);
this.register(File.class, FileSimpledCoder.instance);
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
this.register(AsyncHandler.class, AsyncHandlerSimpledCoder.instance);
this.register(URL.class, URLSimpledCoder.instance);
this.register(URI.class, URISimpledCoder.instance);
//---------------------------------------------------------
this.register(ByteBuffer.class, ByteBufferSimpledCoder.instance);
this.register(boolean[].class, BoolArraySimpledCoder.instance);
this.register(byte[].class, ByteArraySimpledCoder.instance);
this.register(short[].class, ShortArraySimpledCoder.instance);
@@ -104,6 +111,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(double[].class, DoubleArraySimpledCoder.instance);
this.register(String[].class, StringArraySimpledCoder.instance);
//---------------------------------------------------------
this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class));
this.register(HttpCookie.class, new Creator<HttpCookie>() {
@Override
@Creator.ConstructorParameters({"name", "value"})
@@ -181,12 +189,68 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
}
final String getEntityAlias(Class clazz) {
if (clazz == String.class) return "A";
if (clazz == int.class) return "I";
if (clazz == Integer.class) return "i";
if (clazz == long.class) return "J";
if (clazz == Long.class) return "j";
if (clazz == byte.class) return "B";
if (clazz == Byte.class) return "b";
if (clazz == boolean.class) return "Z";
if (clazz == Boolean.class) return "z";
if (clazz == short.class) return "S";
if (clazz == Short.class) return "s";
if (clazz == char.class) return "C";
if (clazz == Character.class) return "c";
if (clazz == float.class) return "F";
if (clazz == Float.class) return "f";
if (clazz == double.class) return "D";
if (clazz == Double.class) return "d";
if (clazz == String[].class) return "[A";
if (clazz == int[].class) return "[I";
if (clazz == long[].class) return "[J";
if (clazz == byte[].class) return "[B";
if (clazz == boolean[].class) return "[Z";
if (clazz == short[].class) return "[S";
if (clazz == char[].class) return "[C";
if (clazz == float[].class) return "[F";
if (clazz == double[].class) return "[D";
ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class);
if (ce != null && findEntityAlias(ce.value()) == null) entitys.put(ce.value(), clazz);
return ce == null ? clazz.getName() : ce.value();
}
final Class getEntityAlias(String name) {
if ("A".equals(name)) return String.class;
if ("I".equals(name)) return int.class;
if ("i".equals(name)) return Integer.class;
if ("J".equals(name)) return long.class;
if ("j".equals(name)) return Long.class;
if ("B".equals(name)) return byte.class;
if ("b".equals(name)) return Byte.class;
if ("Z".equals(name)) return boolean.class;
if ("z".equals(name)) return Boolean.class;
if ("S".equals(name)) return short.class;
if ("s".equals(name)) return Short.class;
if ("C".equals(name)) return char.class;
if ("c".equals(name)) return Character.class;
if ("F".equals(name)) return float.class;
if ("f".equals(name)) return Float.class;
if ("D".equals(name)) return double.class;
if ("d".equals(name)) return Double.class;
if ("[A".equals(name)) return String[].class;
if ("[I".equals(name)) return int[].class;
if ("[J".equals(name)) return long[].class;
if ("[B".equals(name)) return byte[].class;
if ("[Z".equals(name)) return boolean[].class;
if ("[S".equals(name)) return short[].class;
if ("[C".equals(name)) return char[].class;
if ("[F".equals(name)) return float[].class;
if ("[D".equals(name)) return double[].class;
Class clazz = findEntityAlias(name);
try {
return clazz == null ? Class.forName(name) : clazz;
@@ -390,6 +454,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
decoder = new ArrayDecoder(this, type);
} else if (Collection.class.isAssignableFrom(clazz)) {
decoder = new CollectionDecoder(this, type);
} else if (Stream.class.isAssignableFrom(clazz)) {
decoder = new StreamDecoder(this, type);
} else if (Map.class.isAssignableFrom(clazz)) {
decoder = new MapDecoder(this, type);
} else if (clazz == Object.class) {
@@ -473,6 +539,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
encoder = new ArrayEncoder(this, type);
} else if (Collection.class.isAssignableFrom(clazz)) {
encoder = new CollectionEncoder(this, type);
} else if (Stream.class.isAssignableFrom(clazz)) {
encoder = new StreamEncoder(this, type);
} else if (Map.class.isAssignableFrom(clazz)) {
encoder = new MapEncoder(this, type);
} else if (clazz == Object.class) {

View File

@@ -0,0 +1,25 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
/**
* Mask接口
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public interface ConvertMask {
default byte mask(byte value) {
return value;
}
default byte unmask(byte value) {
return value;
}
}

View File

@@ -6,8 +6,11 @@
package org.redkale.convert;
/**
* 序列化类型枚举,结合&#64;ConvertColumn使用
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public enum ConvertType {

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute;
/**
* 字段的反序列化操作类
*
* <p>
* 详情见: https://redkale.org

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import java.lang.reflect.Type;
/**
* 反序列化操作类
*
* <p>
* 详情见: https://redkale.org

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute;
/**
* 字段的序列化操作类
*
* <p>
* 详情见: https://redkale.org

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import java.lang.reflect.Type;
/**
* 序列化操作类
*
* <p>
* 详情见: https://redkale.org

View File

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

View File

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

View File

@@ -13,6 +13,7 @@ import java.util.Set;
import org.redkale.util.*;
/**
* 自定义对象的反序列化操作类
*
* <p>
* 详情见: https://redkale.org
@@ -66,7 +67,8 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
clazz = (Class) type;
}
this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
final Set<DeMember> list = new HashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
try {
@@ -75,7 +77,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(field.getGenericType(), this.type);
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t)));
}
final boolean reversible = factory.isReversible();
@@ -85,6 +87,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (method.isSynthetic()) continue;
if (method.getName().length() < 4) continue;
if (!method.getName().startsWith("set")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (method.getParameterTypes().length != 1) continue;
if (method.getReturnType() != void.class) continue;
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
@@ -97,7 +100,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(method.getGenericParameterTypes()[0], this.type);
Type t = TypeToken.createClassType(method.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t)));
}
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
@@ -113,7 +116,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
//不存在setter方法
try {
Field f = clazz.getDeclaredField(constructorField);
Type t = ObjectEncoder.createClassType(f.getGenericType(), this.type);
Type t = TypeToken.createClassType(f.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t)));
} catch (NoSuchFieldException nsfe) { //不存在field 可能存在getter方法
char[] fs = constructorField.toCharArray();
@@ -125,7 +128,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
} catch (NoSuchMethodException ex) {
getter = clazz.getMethod("is" + mn);
}
Type t = ObjectEncoder.createClassType(getter.getGenericParameterTypes()[0], this.type);
Type t = TypeToken.createClassType(getter.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
}
}

View File

@@ -10,6 +10,7 @@ import java.util.*;
import org.redkale.util.*;
/**
* 自定义对象的序列化操作类
*
* <p>
* 详情见: https://redkale.org
@@ -67,7 +68,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = createClassType(field.getGenericType(), this.type);
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t)));
}
for (final Method method : clazz.getMethods()) {
@@ -77,6 +78,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (method.getName().length() < 3) continue;
if (method.getName().equals("getClass")) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() == void.class) continue;
if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
@@ -89,7 +91,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = createClassType(method.getGenericReturnType(), this.type);
Type t = TypeToken.createClassType(method.getGenericReturnType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t)));
}
this.members = list.toArray(new EnMember[list.size()]);
@@ -144,42 +146,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
}
static Type createClassType(final Type type, final Type declaringType0) {
if (TypeToken.isClassType(type)) return type;
if (type instanceof ParameterizedType) { // e.g. Map<String, String>
final ParameterizedType pt = (ParameterizedType) type;
final Type[] paramTypes = pt.getActualTypeArguments();
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = createClassType(paramTypes[i], declaringType0);
}
return TypeToken.createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes);
}
Type declaringType = declaringType0;
if (declaringType instanceof Class) {
do {
declaringType = ((Class) declaringType).getGenericSuperclass();
if (declaringType == Object.class) return Object.class;
} while (declaringType instanceof Class);
}
//存在通配符则declaringType 必须是 ParameterizedType
if (!(declaringType instanceof ParameterizedType)) return Object.class;
final ParameterizedType declaringPType = (ParameterizedType) declaringType;
final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters();
final Type[] desTypes = declaringPType.getActualTypeArguments();
if (type instanceof WildcardType) { // e.g. <? extends Serializable>
final WildcardType wt = (WildcardType) type;
for (Type f : wt.getUpperBounds()) {
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
return type;
}
//
// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
// if (type instanceof Class) { //e.g. String
@@ -228,7 +194,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
// }
// return type;
// }
static boolean contains(String[] values, String value) {
for (String str : values) {
if (str.equals(value)) return true;

View File

@@ -6,6 +6,7 @@
package org.redkale.convert;
/**
* 反序列化的数据读取流
*
* <p>
* 详情见: https://redkale.org
@@ -42,6 +43,7 @@ public abstract class Reader {
* 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。
*
* @param clazz 类名
*
* @return 返回字段数
*/
public String readObjectB(final Class clazz) {
@@ -86,6 +88,7 @@ public abstract class Reader {
* 根据字段读取字段对应的DeMember
*
* @param members DeMember的全量集合
*
* @return 匹配的DeMember
*/
public abstract DeMember readFieldName(final DeMember[] members);

View File

@@ -9,6 +9,8 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 简易类的序列化和反序列化操作类 <br>
* 能序列化为Boolean、Number或者字符串的类视为简易类 <br>
*
* <p>
* 详情见: https://redkale.org

View File

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

View File

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

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Attribute;
/**
* 序列化的数据输出流
*
* <p>
* 详情见: https://redkale.org
@@ -37,7 +38,7 @@ public abstract class Writer {
* @return boolean
*/
public abstract boolean needWriteClassName();
/**
* 写入类名
*

View File

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

View File

@@ -10,6 +10,7 @@ import java.util.function.*;
import org.redkale.util.Utility;
/**
* 以ByteBuffer为数据载体的BsonWriter
*
* <p>
* 详情见: https://redkale.org

View File

@@ -15,21 +15,21 @@ import org.redkale.util.*;
/**
* <blockquote><pre>
* BSON协议格式:
* 1). 基本数据类型: 直接转换成byte[]
* 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
* 3). String: length(4 bytes) + byte[](utf8);
* 4). 数组: length(4 bytes) + byte[]...
* 5). Object:
* 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
* 2. 空字符串(SmallString)
* 3. SIGN_OBJECTB 标记位值固定为0xBB (short)
* 4. 循环字段值:
* 1) 基本数据类型: 直接转换成byte[]
* 2) SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
* 3) String: length(4 bytes) + byte[](utf8);
* 4) 数组: length(4 bytes) + byte[]...
* 5) Object:
* 1 realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
* 2 空字符串(SmallString)
* 3 SIGN_OBJECTB 标记位值固定为0xBB (short)
* 4 循环字段值:
* 4.1 SIGN_HASNEXT 标记位值固定为1 (byte)
* 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object
* 4.3 字段名 (SmallString)
* 4.4 字段的值Object
* 5. SIGN_NONEXT 标记位值固定为0 (byte)
* 6. SIGN_OBJECTE 标记位值固定为0xEE (short)
* 5 SIGN_NONEXT 标记位值固定为0 (byte)
* 6 SIGN_OBJECTE 标记位值固定为0xEE (short)
*
* </pre></blockquote>
* <p>
@@ -61,7 +61,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
//------------------------------ reader -----------------------------------------------------------
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
return new BsonByteBufferReader(buffers);
return new BsonByteBufferReader((ConvertMask) null, buffers);
}
public BsonReader pollBsonReader(final InputStream in) {
@@ -116,7 +116,12 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
if (type == null || buffers.length < 1) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(buffers));
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader((ConvertMask) null, buffers));
}
public <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) {
if (type == null || buffers.length < 1) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(mask, buffers));
}
public <T> T convertFrom(final Type type, final BsonReader reader) {

View File

@@ -7,8 +7,10 @@ package org.redkale.convert.bson;
import java.io.Serializable;
import org.redkale.convert.*;
import org.redkale.util.AnyValue;
/**
* BSON的ConvertFactory
*
* <p>
* 详情见: https://redkale.org
@@ -27,6 +29,9 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
static {
instance.register(Serializable.class, objectDecoder);
instance.register(Serializable.class, objectEncoder);
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
}
private BsonFactory(BsonFactory parent, boolean tiny) {

View File

@@ -5,13 +5,13 @@
*/
package org.redkale.convert.bson;
import java.util.function.*;
import org.redkale.convert.*;
import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
* BSON数据源
*
* <p>
* 详情见: https://redkale.org
@@ -42,19 +42,7 @@ public class BsonReader extends Reader {
}
public static ObjectPool<BsonReader> createPool(int max) {
return new ObjectPool<BsonReader>(max, new Creator<BsonReader>() {
@Override
public BsonReader create(Object... params) {
return new BsonReader();
}
}, null, new Predicate<BsonReader>() {
@Override
public boolean test(BsonReader t) {
return t.recycle();
}
});
return new ObjectPool<>(max, (Object... params) -> new BsonReader(), null, (t) -> t.recycle());
}
public BsonReader(byte[] bytes) {
@@ -164,7 +152,7 @@ public class BsonReader extends Reader {
if (bt == Reader.SIGN_NULL) return null;
if (bt != SIGN_OBJECTB) {
throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB)
+ " (position = " + position + ") but '" + currentByte() + "'");
+ " (position = " + position + ") but '" + currentByte() + "'");
}
return "";
}
@@ -173,7 +161,7 @@ public class BsonReader extends Reader {
public final void readObjectE(final Class clazz) {
if (readShort() != SIGN_OBJECTE) {
throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE)
+ " (position = " + position + ") but '" + currentByte() + "'");
+ " (position = " + position + ") but '" + currentByte() + "'");
}
}
@@ -223,7 +211,7 @@ public class BsonReader extends Reader {
byte b = readByte();
if (b == SIGN_HASNEXT) return true;
if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT)
+ " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")");
+ " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")");
return false;
}
@@ -272,19 +260,19 @@ public class BsonReader extends Reader {
@Override
public int readInt() {
return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16)
| ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
| ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
}
@Override
public long readLong() {
return ((((long) content[++this.position] & 0xff) << 56)
| (((long) content[++this.position] & 0xff) << 48)
| (((long) content[++this.position] & 0xff) << 40)
| (((long) content[++this.position] & 0xff) << 32)
| (((long) content[++this.position] & 0xff) << 24)
| (((long) content[++this.position] & 0xff) << 16)
| (((long) content[++this.position] & 0xff) << 8)
| (((long) content[++this.position] & 0xff)));
| (((long) content[++this.position] & 0xff) << 48)
| (((long) content[++this.position] & 0xff) << 40)
| (((long) content[++this.position] & 0xff) << 32)
| (((long) content[++this.position] & 0xff) << 24)
| (((long) content[++this.position] & 0xff) << 16)
| (((long) content[++this.position] & 0xff) << 8)
| (((long) content[++this.position] & 0xff)));
}
@Override

View File

@@ -9,7 +9,7 @@ import java.io.*;
import org.redkale.convert.*;
/**
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
@@ -21,6 +21,7 @@ class BsonStreamReader extends BsonByteBufferReader {
private byte currByte;
protected BsonStreamReader(InputStream in) {
super((ConvertMask) null);
this.in = in;
}

View File

@@ -6,7 +6,6 @@
package org.redkale.convert.bson;
import java.nio.ByteBuffer;
import java.util.function.Predicate;
import org.redkale.convert.*;
import org.redkale.util.*;
@@ -28,19 +27,7 @@ public class BsonWriter extends Writer {
protected boolean tiny;
public static ObjectPool<BsonWriter> createPool(int max) {
return new ObjectPool<BsonWriter>(max, new Creator<BsonWriter>() {
@Override
public BsonWriter create(Object... params) {
return new BsonWriter();
}
}, null, new Predicate<BsonWriter>() {
@Override
public boolean test(BsonWriter t) {
return t.recycle();
}
});
return new ObjectPool<>(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());
}
public byte[] toArray() {
@@ -82,6 +69,7 @@ public class BsonWriter extends Writer {
* 扩充指定长度的缓冲区
*
* @param len 扩容长度
*
* @return 固定0
*/
protected int expand(int len) {
@@ -248,11 +236,11 @@ public class BsonWriter extends Writer {
return;
}
char[] chars = Utility.charArray(value);
if (chars.length > 255) throw new ConvertException("'" + value + "' has very long length");
if (chars.length > 255) throw new ConvertException("'" + value + "' have very long length");
byte[] bytes = new byte[chars.length + 1];
bytes[0] = (byte) chars.length;
for (int i = 0; i < chars.length; i++) {
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' has double-word");
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' have double-word");
bytes[i + 1] = (byte) chars[i];
}
writeTo(bytes);

View File

@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.*;
import org.redkale.util.AsyncHandler;
/**
* AsyncHandlerSimpledCoder 的SimpledCoder实现, 只输出null
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class AsyncHandlerSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, AsyncHandler> {
public static final AsyncHandlerSimpledCoder instance = new AsyncHandlerSimpledCoder();
@Override
public void convertTo(W out, AsyncHandler value) {
out.writeObjectNull(AsyncHandler.class);
}
@Override
public AsyncHandler convertFrom(R in) {
in.readObjectB(AsyncHandler.class);
return null;
}
}

View File

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

View File

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

View File

@@ -38,7 +38,7 @@ public class TypeSimpledCoder<R extends Reader, W extends Writer> extends Simple
if (str == null) return null;
try {
return Class.forName(str);
} catch (Exception e) {
} catch (Throwable e) {
return null;
}
}

View File

@@ -11,9 +11,10 @@ import org.redkale.convert.*;
import static org.redkale.convert.Reader.*;
/**
*
* 以ByteBuffer为数据载体的JsonReader <br>
*
* 只支持UTF-8格式
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
@@ -28,7 +29,10 @@ public class JsonByteBufferReader extends JsonReader {
private ByteBuffer currentBuffer;
protected JsonByteBufferReader(ByteBuffer... buffers) {
protected ConvertMask mask;
protected JsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) {
this.mask = mask;
this.buffers = buffers;
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
}
@@ -40,19 +44,20 @@ public class JsonByteBufferReader extends JsonReader {
this.currentChar = 0;
this.currentBuffer = null;
this.buffers = null;
this.mask = null;
return false;
}
protected byte nextByte() {
if (this.currentBuffer.hasRemaining()) {
this.position++;
return this.currentBuffer.get();
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
}
for (;;) {
this.currentBuffer = this.buffers[++this.currentIndex];
if (this.currentBuffer.hasRemaining()) {
this.position++;
return this.currentBuffer.get();
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
}
}
}

View File

@@ -13,6 +13,7 @@ import org.redkale.convert.*;
import org.redkale.util.*;
/**
* 以ByteBuffer为数据载体的JsonWriter
*
* <p>
* 详情见: https://redkale.org

View File

@@ -48,7 +48,7 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
//------------------------------ reader -----------------------------------------------------------
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
return new JsonByteBufferReader(buffers);
return new JsonByteBufferReader((ConvertMask) null, buffers);
}
public JsonReader pollJsonReader(final InputStream in) {
@@ -111,7 +111,12 @@ public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
if (type == null || buffers == null || buffers.length == 0) return null;
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader(buffers));
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers));
}
public <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) {
if (type == null || buffers == null || buffers.length == 0) return null;
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader(mask, buffers));
}
public <T> T convertFrom(final Type type, final JsonReader reader) {

View File

@@ -10,9 +10,10 @@ import java.math.BigInteger;
import java.net.*;
import org.redkale.convert.*;
import org.redkale.convert.ext.*;
import org.redkale.util.DLong;
import org.redkale.util.*;
/**
* JSON的ConvertFactory
*
* <p>
* 详情见: https://redkale.org
@@ -29,6 +30,9 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
instance.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
instance.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
instance.register(Serializable.class, instance.loadEncoder(Object.class));
instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class));
instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
}
private JsonFactory(JsonFactory parent, boolean tiny) {

View File

@@ -10,6 +10,7 @@ import static org.redkale.convert.Reader.*;
import org.redkale.util.*;
/**
* JSON数据源
*
* <p>
* 详情见: https://redkale.org

View File

@@ -11,7 +11,7 @@ import org.redkale.convert.*;
/**
*
* 详情见: https://redkale.org
*
*
* @author zhangjx
*/
class JsonStreamReader extends JsonByteBufferReader {
@@ -19,6 +19,7 @@ class JsonStreamReader extends JsonByteBufferReader {
private InputStream in;
protected JsonStreamReader(InputStream in) {
super((ConvertMask) null);
this.in = in;
}

View File

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

View File

@@ -14,50 +14,63 @@ import java.util.logging.*;
import org.redkale.convert.bson.*;
import org.redkale.convert.json.*;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
* 服务器上下文对象
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public class Context {
private static final Charset UTF8 = Charset.forName("UTF-8");
//服务启动时间
protected final long serverStartTime;
//Server的线程池
protected final ExecutorService executor;
//ByteBuffer的容量默认8K
protected final int bufferCapacity;
//ByteBuffer对象池
protected final ObjectPool<ByteBuffer> bufferPool;
//Response对象池
protected final ObjectPool<Response> responsePool;
//服务的根Servlet
protected final PrepareServlet prepare;
//服务的监听地址
private final InetSocketAddress address;
//字符集
protected final Charset charset;
//请求内容的大小上限, 默认64K
protected final int maxbody;
//IO读取的超时时间
protected final int readTimeoutSecond;
//IO写入的超时时间
protected final int writeTimeoutSecond;
//日志Logger
protected final Logger logger;
//BSON操作工厂
protected final BsonFactory bsonFactory;
//JSON操作工厂
protected final JsonFactory jsonFactory;
protected final WatchFactory watch;
public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,
final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final WatchFactory watch,
final int readTimeoutSecond, final int writeTimeoutSecond) {
final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final int readTimeoutSecond, final int writeTimeoutSecond) {
this.serverStartTime = serverStartTime;
this.logger = logger;
this.executor = executor;
@@ -68,7 +81,6 @@ public class Context {
this.charset = UTF8.equals(charset) ? null : charset;
this.address = address;
this.prepare = prepare;
this.watch = watch;
this.readTimeoutSecond = readTimeoutSecond;
this.writeTimeoutSecond = writeTimeoutSecond;
this.jsonFactory = JsonFactory.root();
@@ -91,8 +103,12 @@ public class Context {
return charset;
}
public void submit(Runnable r) {
executor.submit(r);
public Future<?> submitAsync(Runnable r) {
return executor.submit(r);
}
public void runAsync(Runnable r) {
executor.execute(r);
}
public int getBufferCapacity() {
@@ -111,6 +127,13 @@ public class Context {
bufferPool.offer(buffer);
}
public void offerBuffer(ByteBuffer... buffers) {
if (buffers == null) return;
for (ByteBuffer buffer : buffers) {
bufferPool.offer(buffer);
}
}
public Logger getLogger() {
return logger;
}

View File

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

View File

@@ -11,8 +11,11 @@ import java.util.logging.*;
import org.redkale.util.*;
/**
* 根Servlet的处理逻辑类
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
@SuppressWarnings("unchecked")

View File

@@ -10,10 +10,14 @@ import java.nio.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.Predicate;
import java.util.logging.*;
import org.redkale.util.*;
/**
* 根Servlet 一个Server只能存在一个根Servlet
*
* 用于分发Request请求
*
* <p>
* 详情见: https://redkale.org
@@ -31,9 +35,135 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
protected final AtomicLong illRequestCounter = new AtomicLong(); //错误请求次数
protected final Set<S> servlets = new HashSet<>();
private final Object lock1 = new Object();
protected final Map<K, S> mappings = new HashMap<>();
private Set<S> servlets = new HashSet<>();
private final Object lock2 = new Object();
private Map<K, S> mappings = new HashMap<>();
private final List<Filter<C, R, P>> filters = new ArrayList<>();
protected Filter<C, R, P> headFilter;
protected void putServlet(S servlet) {
synchronized (lock1) {
Set<S> newservlets = new HashSet<>(servlets);
newservlets.add(servlet);
this.servlets = newservlets;
}
}
protected void removeServlet(S servlet) {
synchronized (lock1) {
Set<S> newservlets = new HashSet<>(servlets);
newservlets.remove(servlet);
this.servlets = newservlets;
}
}
protected void putMapping(K key, S servlet) {
synchronized (lock2) {
Map<K, S> newmappings = new HashMap<>(mappings);
newmappings.put(key, servlet);
this.mappings = newmappings;
}
}
protected void removeMapping(K key) {
synchronized (lock2) {
if (mappings.containsKey(key)) {
Map<K, S> newmappings = new HashMap<>(mappings);
newmappings.remove(key);
this.mappings = newmappings;
}
}
}
protected void removeMapping(S servlet) {
synchronized (lock2) {
List<K> keys = new ArrayList<>();
Map<K, S> newmappings = new HashMap<>(mappings);
for (Map.Entry<K, S> en : newmappings.entrySet()) {
if (en.getValue().equals(servlet)) {
keys.add(en.getKey());
}
}
for (K key : keys) newmappings.remove(key);
this.mappings = newmappings;
}
}
protected S mappingServlet(K key) {
return mappings.get(key);
}
@Override
public void init(C context, AnyValue config) {
synchronized (filters) {
if (!filters.isEmpty()) {
Collections.sort(filters);
for (Filter<C, R, P> filter : filters) {
filter.init(context, config);
}
this.headFilter = filters.get(0);
Filter<C, R, P> filter = this.headFilter;
for (int i = 1; i < filters.size(); i++) {
filter._next = filters.get(i);
filter = filter._next;
}
}
}
}
@Override
public void destroy(C context, AnyValue config) {
synchronized (filters) {
if (!filters.isEmpty()) {
for (Filter filter : filters) {
filter.destroy(context, config);
}
}
}
}
public void addFilter(Filter<C, R, P> filter, AnyValue conf) {
filter._conf = conf;
synchronized (filters) {
this.filters.add(filter);
}
}
public Filter<C, R, P> removeFilter(Class<? extends Filter<C, R, P>> filterClass) {
return removeFilter(f -> filterClass.equals(f.getClass()));
}
public Filter<C, R, P> removeFilter(String filterName) {
return removeFilter(f -> filterName.equals(f.resourceName()));
}
public Filter<C, R, P> removeFilter(Predicate<Filter<C, R, P>> predicate) {
if (this.headFilter == null || predicate == null) return null;
synchronized (filters) {
Filter filter = this.headFilter;
Filter prev = null;
do {
if (predicate.test(filter)) break;
prev = filter;
} while ((filter = filter._next) != null);
if (filter != null) {
if (prev == null) {
this.headFilter = filter._next;
} else {
prev._next = filter._next;
}
filter._next = null;
this.filters.remove(filter);
}
return filter;
}
}
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
@@ -47,7 +177,9 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
} else if (rs == 0) {
response.context.offerBuffer(buffer);
request.prepare();
this.execute(request, response);
response.filter = this.headFilter;
response.servlet = this;
response.nextEvent();
} else {
buffer.clear();
final AtomicInteger ai = new AtomicInteger(rs);
@@ -64,7 +196,9 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
response.context.offerBuffer(buffer);
request.prepare();
try {
execute(request, response);
response.filter = PrepareServlet.this.headFilter;
response.servlet = PrepareServlet.this;
response.nextEvent();
} catch (Exception e) {
illRequestCounter.incrementAndGet();
response.finish(true);

View File

@@ -11,14 +11,27 @@ import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/**
* 协议底层Server
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public abstract class ProtocolServer {
//创建数
protected final AtomicLong createCounter = new AtomicLong();
//关闭数
protected final AtomicLong closedCounter = new AtomicLong();
//在线数
protected final AtomicLong livingCounter = new AtomicLong();
public abstract void open() throws IOException;
public abstract void bind(SocketAddress local, int backlog) throws IOException;
@@ -33,6 +46,18 @@ public abstract class ProtocolServer {
public abstract AsynchronousChannelGroup getChannelGroup();
public long getCreateCount() {
return createCounter.longValue();
}
public long getClosedCount() {
return closedCounter.longValue();
}
public long getLivingCount() {
return livingCounter.longValue();
}
//---------------------------------------------------------------------
public static ProtocolServer create(String protocol, Context context) {
if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context);
@@ -91,7 +116,7 @@ public abstract class ProtocolServer {
SocketAddress address = serchannel.receive(buffer);
buffer.flip();
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
context.submit(new PrepareRunner(context, conn, buffer));
context.runAsync(new PrepareRunner(context, conn, buffer));
} catch (Exception e) {
context.offerBuffer(buffer);
}
@@ -116,6 +141,20 @@ public abstract class ProtocolServer {
return null;
}
@Override
public long getCreateCount() {
return -1;
}
@Override
public long getClosedCount() {
return -1;
}
@Override
public long getLivingCount() {
return -1;
}
}
private static final class ProtocolTCPServer extends ProtocolServer {
@@ -159,7 +198,12 @@ public abstract class ProtocolServer {
@Override
public void completed(final AsynchronousSocketChannel channel, Void attachment) {
serchannel.accept(null, this);
context.submit(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null));
createCounter.incrementAndGet();
livingCounter.incrementAndGet();
AsyncConnection conn = AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond);
conn.livingCounter = livingCounter;
conn.closedCounter = closedCounter;
context.submitAsync(new PrepareRunner(context, conn, null));
}
@Override

View File

@@ -11,6 +11,7 @@ import org.redkale.convert.bson.BsonConvert;
import org.redkale.convert.json.JsonConvert;
/**
* 协议请求对象
*
* <p>
* 详情见: https://redkale.org

View File

@@ -5,11 +5,13 @@
*/
package org.redkale.net;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.util.function.BiConsumer;
/**
* 协议响应对象
*
* <p>
* 详情见: https://redkale.org
@@ -33,6 +35,10 @@ public abstract class Response<C extends Context, R extends Request<C>> {
protected BiConsumer<R, Response<C, R>> recycleListener;
protected Filter<C, R, ? extends Response<C, R>> filter;
protected Servlet<C, R, ? extends Response<C, R>> servlet;
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
@Override
@@ -113,10 +119,12 @@ public abstract class Response<C extends Context, R extends Request<C>> {
recycleListener = null;
}
this.output = null;
this.filter = null;
this.servlet = null;
request.recycle();
if (channel != null) {
if (keepAlive) {
this.context.submit(new PrepareRunner(context, channel, null));
this.context.runAsync(new PrepareRunner(context, channel, null));
} else {
try {
if (channel.isOpen()) channel.close();
@@ -139,38 +147,99 @@ public abstract class Response<C extends Context, R extends Request<C>> {
this.request.createtime = System.currentTimeMillis();
}
protected void setFilter(Filter<C, R, Response<C, R>> filter) {
this.filter = filter;
}
protected void thenEvent(Servlet servlet) {
this.servlet = servlet;
}
@SuppressWarnings("unchecked")
public void nextEvent() throws IOException {
if (this.filter != null) {
Filter runner = this.filter;
this.filter = this.filter._next;
runner.doFilter(request, this);
return;
}
if (this.servlet != null) {
Servlet s = this.servlet;
this.servlet = null;
s.execute(request, this);
}
}
/**
* 使用 public void recycleListener(BiConsumer recycleListener) 代替
*
* @param recycleListener BiConsumer
*
* @deprecated
*/
@Deprecated
public void setRecycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
this.recycleListener = recycleListener;
}
public void recycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
this.recycleListener = recycleListener;
}
public Object getOutput() {
return output;
}
/**
* 是否已关闭
*
* @return boolean
*/
public boolean isClosed() {
return !this.inited;
}
public void finish() {
this.finish(false);
}
public void finish(boolean kill) {
if (!this.inited) return; //避免重复关闭
//System.println("耗时: " + (System.currentTimeMillis() - request.createtime));
if (kill) refuseAlive();
this.context.responsePool.offer(this);
}
public void finish(final byte[] bs) {
if (!this.inited) return; //避免重复关闭
if (this.context.bufferCapacity == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
buffer.flip();
this.finish(buffer);
} else {
this.finish(ByteBuffer.wrap(bs));
}
}
public void finish(ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffer, buffer, finishHandler);
}
public void finish(boolean kill, ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffer, buffer, finishHandler);
}
public void finish(ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffers, buffers, finishHandler2);
}
public void finish(boolean kill, ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffers, buffers, finishHandler2);
}

View File

@@ -15,7 +15,6 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import org.redkale.util.AnyValue;
import org.redkale.watch.WatchFactory;
/**
*
@@ -39,9 +38,6 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
//服务的启动时间
protected final long serverStartTime;
//监控对象
protected final WatchFactory watch;
//服务的名称
protected String name;
@@ -93,11 +89,10 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
//IO写入 的超时秒数小于1视为不设置
protected int writeTimeoutSecond;
protected Server(long serverStartTime, String protocol, PrepareServlet<K, C, R, P, S> servlet, final WatchFactory watch) {
protected Server(long serverStartTime, String protocol, PrepareServlet<K, C, R, P, S> servlet) {
this.serverStartTime = serverStartTime;
this.protocol = protocol;
this.prepare = servlet;
this.watch = watch;
}
public void init(final AnyValue config) throws Exception {
@@ -109,7 +104,8 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
this.readTimeoutSecond = config.getIntValue("readTimeoutSecond", 0);
this.writeTimeoutSecond = config.getIntValue("writeTimeoutSecond", 0);
this.maxbody = config.getIntValue("maxbody", 64 * 1024);
this.bufferCapacity = config.getIntValue("bufferCapacity", 8 * 1024);
int bufCapacity = config.getIntValue("bufferCapacity", 8 * 1024);
this.bufferCapacity = bufCapacity < 256 ? 256 : bufCapacity;
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 16);
this.bufferPoolSize = config.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 512);
this.responsePoolSize = config.getIntValue("responsePoolSize", Runtime.getRuntime().availableProcessors() * 256);
@@ -161,7 +157,6 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
public void start() throws IOException {
this.context = this.createContext();
this.prepare.init(this.context, config);
if (this.watch != null) this.watch.inject(this.prepare);
this.serverChannel = ProtocolServer.create(this.protocol, context);
this.serverChannel.open();
if (this.serverChannel.supportedOptions().contains(StandardSocketOptions.TCP_NODELAY)) {
@@ -190,6 +185,30 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
logger.info(this.getClass().getSimpleName() + " shutdown in " + e + " ms");
}
/**
* 销毁Servlet
*
* @param servlet Servlet
*/
public void destroyServlet(S servlet) {
servlet.destroy(context, this.prepare.getServletConf(servlet));
}
//创建数
public long getCreateConnectionCount() {
return serverChannel == null ? -1 : serverChannel.getCreateCount();
}
//关闭数
public long getClosedConnectionCount() {
return serverChannel == null ? -1 : serverChannel.getClosedCount();
}
//在线数
public long getLivingConnectionCount() {
return serverChannel == null ? -1 : serverChannel.getLivingCount();
}
protected Format createFormat() {
String sf = "0";
if (this.threads > 10) sf = "00";

View File

@@ -9,6 +9,7 @@ import org.redkale.util.AnyValue;
import java.io.IOException;
/**
* 协议请求处理类
*
* <p>
* 详情见: https://redkale.org

View File

@@ -13,7 +13,6 @@ import java.util.concurrent.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.redkale.util.ObjectPool;
import org.redkale.watch.WatchFactory;
/**
* 传输客户端
@@ -44,14 +43,12 @@ public final class Transport {
protected final String name; //即<group>的name属性
protected final String kind; //即<group>的kind属性
protected final String subprotocol; //即<group>的subprotocol属性
protected final boolean tcp;
protected final String protocol;
protected final WatchFactory watch;
protected final AsynchronousChannelGroup group;
protected final InetSocketAddress clientAddress;
@@ -62,16 +59,15 @@ public final class Transport {
protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>();
public Transport(String name, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool,
public Transport(String name, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this(name, DEFAULT_PROTOCOL, watch, kind, transportBufferPool, transportChannelGroup, clientAddress, addresses);
this(name, DEFAULT_PROTOCOL, subprotocol, transportBufferPool, transportChannelGroup, clientAddress, addresses);
}
public Transport(String name, String protocol, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool,
public Transport(String name, String protocol, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this.name = name;
this.watch = watch;
this.kind = kind == null ? "" : kind.trim();
this.subprotocol = subprotocol == null ? "" : subprotocol.trim();
this.protocol = protocol;
this.tcp = "TCP".equalsIgnoreCase(protocol);
this.group = transportChannelGroup;
@@ -83,14 +79,17 @@ public final class Transport {
public Transport(final Collection<Transport> transports) {
Transport first = null;
List<String> tmpgroup = new ArrayList<>();
for (Transport t : transports) {
if (first == null) first = t;
tmpgroup.add(t.name);
if (transports != null) {
for (Transport t : transports) {
if (first == null) first = t;
tmpgroup.add(t.name);
}
}
if (first == null) throw new NullPointerException("Collection<Transport> is null or empty");
//必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name
this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";"));
this.watch = first.watch;
this.kind = first.kind;
//this.watch = first.watch;
this.subprotocol = first.subprotocol;
this.protocol = first.protocol;
this.tcp = "TCP".equalsIgnoreCase(first.protocol);
this.group = first.group;
@@ -118,8 +117,8 @@ public final class Transport {
return name;
}
public String getKind() {
return kind;
public String getSubprotocol() {
return subprotocol;
}
public void close() {
@@ -162,7 +161,7 @@ public final class Transport {
public AsyncConnection pollConnection(SocketAddress addr) {
if (addr == null && remoteAddres.length == 1) addr = remoteAddres[0];
final boolean rand = addr == null;
if (rand && remoteAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") has no remoteAddress list");
if (rand && remoteAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") have no remoteAddress list");
try {
if (tcp) {
AsynchronousSocketChannel channel = null;

View File

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

View File

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

View File

@@ -8,8 +8,11 @@ package org.redkale.net;
import java.util.concurrent.*;
/**
* 协议处理的自定义线程类
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public class WorkThread extends Thread {
@@ -22,8 +25,8 @@ public class WorkThread extends Thread {
this.setDaemon(true);
}
public void submit(Runnable runner) {
executor.submit(runner);
public void runAsync(Runnable runner) {
executor.execute(runner);
}
public ExecutorService getExecutor() {

View File

@@ -8,12 +8,14 @@ package org.redkale.net.http;
import java.io.IOException;
/**
* 默认Servlet, 没有配置RestHttpServlet实现类则使用该默认类
* 默认Servlet, 没有配置RestServlet实现类则使用该默认类
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Deprecated
public class DefaultRestServlet extends RestHttpServlet<Object> {
@Override
@@ -21,9 +23,4 @@ public class DefaultRestServlet extends RestHttpServlet<Object> {
return new Object();
}
@Override
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true;
}
}

View File

@@ -22,31 +22,31 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.service.RetResult;
/**
* 直接只用HttpServlet代替, 将在1.9版本移除
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Deprecated
public abstract class HttpBaseServlet extends HttpServlet {
public static final int RET_SERVER_ERROR = 1800_0001;
public static final int RET_METHOD_ERROR = 1800_0002;
/**
* 配合 HttpBaseServlet 使用。
* 当标记为 &#64;AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。
* 使用 org.redkale.util.AuthIgnore 代替
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, TYPE})
@Retention(RUNTIME)
@Deprecated
protected @interface AuthIgnore {
}
@@ -66,18 +66,20 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 配合 &#64;WebAction 使用。
* 用于对&#64;WebAction方法中参数描述
*
* 使用 org.redkale.net.http.HttpParam 代替
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Repeatable(WebParams.class)
@Deprecated
protected @interface WebParam {
String name(); //参数名
@@ -102,17 +104,17 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 配合 HttpBaseServlet 使用
* 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式
*
* 使用 org.redkale.net.http.HttpMapping 替代
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Deprecated
protected @interface WebAction {
int actionid() default 0;
@@ -131,18 +133,45 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 配合 HttpBaseServlet 使用
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
* 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。
* 使用 org.redkale.net.http.HttpMapping 替代
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Deprecated
protected @interface WebMapping {
int actionid() default 0;
String url();
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法
String comment() default ""; //备注描述
boolean inherited() default true; //是否能被继承, 当 HttpBaseServlet 被继承后该方法是否能被子类继承
String result() default "Object"; //输出结果的数据类型
Class[] results() default {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
}
/**
* 使用 org.redkale.net.http.HttpMapping.cacheseconds 替代。
*
* @deprecated
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Deprecated
protected @interface HttpCacheable {
/**
@@ -153,39 +182,124 @@ public abstract class HttpBaseServlet extends HttpServlet {
int seconds() default 15;
}
private Map.Entry<String, Entry>[] actions;
private Map.Entry<String, Entry>[] mappings;
public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException {
private final HttpServlet authSuccessServlet = new HttpServlet() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
Entry entry = (Entry) request.getAttribute("_redkale_entry");
if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
return;
}
response.setBufferHandler(entry.cacheHandler);
}
entry.servlet.execute(request, response);
}
};
private final HttpServlet preSuccessServlet = new HttpServlet() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
for (Map.Entry<String, Entry> en : mappings) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
request.setAttribute("_redkale_entry", entry);
if (entry.ignore) {
authSuccessServlet.execute(request, response);
} else {
HttpBaseServlet.this.authenticate(entry.moduleid, entry.actionid, request, response, authSuccessServlet);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
}
};
/**
* <p>
* 预执行方法在execute方法之前运行通常用于常规统计或基础检测例如 : <br>
* <blockquote><pre>
* &#64;Override
* public void preExecute(final HttpRequest request, final HttpResponse response, HttpServlet next) throws IOException {
* if (finer) response.setRecycleListener((req, resp) -&#62; { //记录处理时间比较长的请求
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
* if (e &#62; 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
* });
* next.execute(request, response);
* }
* </pre></blockquote>
* <p>
*
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @throws IOException IOException
*/
public void preExecute(HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
next.execute(request, response);
}
/**
* 使用 public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException 代替
*
* @param moduleid int
* @param actionid int
* @param request HttpRequest
* @param response HttpResponse
*
* @return boolean
* @throws IOException IOException
* @deprecated
*/
@Deprecated
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true;
}
/**
* <p>
* 用户登录或权限验证, 没有注解为&#64;AuthIgnore 的方法会执行authenticate方法, 若验证成功则必须调用next.execute(request, response);进行下一步操作, 例如: <br>
* <blockquote><pre>
* &#64;Override
* public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
* UserInfo info = currentUser(request);
* if (info == null) {
* response.finishJson(RET_UNLOGIN);
* return;
* } else if (!info.checkAuth(module, actionid)) {
* response.finishJson(RET_AUTHILLEGAL);
* return;
* }
* next.execute(request, response);
* }
* </pre></blockquote>
* <p>
*
*
* @param moduleid 模块ID来自&#64;WebServlet.moduleid()
* @param actionid 操作ID来自&#64;WebMapping.actionid()
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @throws IOException IOException
*/
public abstract void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException;
@Override
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
if (!preExecute(request, response)) return;
for (Map.Entry<String, Entry> en : actions) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
return;
}
response.setBufferHandler(entry.cacheHandler);
}
entry.servlet.execute(request, response);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
preExecute(request, response, preSuccessServlet);
}
public final void preInit(HttpContext context, AnyValue config) {
@@ -193,20 +307,18 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load();
this.actions = new Map.Entry[map.size()];
this.mappings = new Map.Entry[map.size()];
int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) {
actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
}
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
Arrays.sort(actions, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
Arrays.sort(mappings, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
}
public final void postDestroy(HttpContext context, AnyValue config) {
}
public abstract boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException;
protected void setHeader(HttpRequest request, String name, Serializable value) {
request.header.setValue(name, String.valueOf(value));
}
@@ -242,17 +354,20 @@ public abstract class HttpBaseServlet extends HttpServlet {
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
final WebMapping mapping = method.getAnnotation(WebMapping.class);
final WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = action.actionid();
final String name = action.url().trim();
if (mapping == null && action == null) continue;
final boolean inherited = mapping == null ? action.inherited() : mapping.inherited();
if (!inherited && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = mapping == null ? action.actionid() : mapping.actionid();
final String name = mapping == null ? action.url().trim() : mapping.url().trim();
final String[] methods = mapping == null ? action.methods() : mapping.methods();
if (nameset.containsKey(name)) {
if (nameset.get(name) != clz) continue;
throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")");
throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + WebMapping.class.getSimpleName() + "(" + name + ")");
}
nameset.put(name, clz);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method)));
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, methods, method, createHttpServlet(method)));
}
} while ((clz = clz.getSuperclass()) != HttpBaseServlet.class);
return map;
@@ -273,7 +388,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
try {
Class.forName(newDynName.replace('/', '.'));
newDynName += "_" + (++i);
} catch (Exception ex) {
} catch (Throwable ex) {
break;
}
}

View File

@@ -11,11 +11,13 @@ import java.nio.charset.*;
import java.security.*;
import java.util.concurrent.*;
import java.util.logging.*;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.net.*;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
* HTTP服务的上下文对象
*
* <p>
* 详情见: https://redkale.org
@@ -26,11 +28,13 @@ public class HttpContext extends Context {
protected final SecureRandom random = new SecureRandom();
protected final ConcurrentHashMap<Class, Creator> asyncHandlerCreators = new ConcurrentHashMap<>();
public HttpContext(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool,
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) {
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
int readTimeoutSecond, int writeTimeoutSecond) {
super(serverStartTime, logger, executor, bufferCapacity, bufferPool, responsePool, maxbody, charset,
address, prepare, watch, readTimeoutSecond, writeTimeoutSecond);
address, prepare, readTimeoutSecond, writeTimeoutSecond);
random.setSeed(Math.abs(System.nanoTime()));
}
@@ -41,10 +45,6 @@ public class HttpContext extends Context {
return new String(Utility.binToHex(bytes));
}
protected WatchFactory getWatchFactory() {
return watch;
}
protected ExecutorService getExecutor() {
return executor;
}
@@ -53,4 +53,113 @@ public class HttpContext extends Context {
return responsePool;
}
protected <H extends AsyncHandler> Creator<H> loadAsyncHandlerCreator(Class<H> handlerClass) {
Creator<H> creator = asyncHandlerCreators.get(handlerClass);
if (creator == null) {
creator = createAsyncHandlerCreator(handlerClass);
asyncHandlerCreators.put(handlerClass, creator);
}
return creator;
}
private <H extends AsyncHandler> Creator<H> createAsyncHandlerCreator(Class<H> handlerClass) {
//生成规则与SncpAsyncHandler.Factory 很类似
//-------------------------------------------------------------
final boolean handlerinterface = handlerClass.isInterface();
final String handlerClassName = handlerClass.getName().replace('.', '/');
final String handlerName = AsyncHandler.class.getName().replace('.', '/');
final String handlerDesc = Type.getDescriptor(AsyncHandler.class);
final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + AsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
AsmMethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName});
{ //handler 属性
fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null);
fv.visitEnd();
}
{//构造方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + handlerDesc + ")V", null, null));
//mv.setDebug(true);
{
av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "handler");
av1.visitEnd();
}
av0.visitEnd();
}
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
Class returnType = method.getReturnType();
if (returnType == void.class) {
mv.visitInsn(RETURN);
mv.visitMaxs(0, 1);
} else if (returnType.isPrimitive()) {
mv.visitInsn(ICONST_0);
if (returnType == long.class) {
mv.visitInsn(LRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == float.class) {
mv.visitInsn(FRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == double.class) {
mv.visitInsn(DRETURN);
mv.visitMaxs(2, 1);
} else {
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
}
} else {
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
}
mv.visitEnd();
}
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Class<AsyncHandler> newHandlerClazz = (Class<AsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
return (Creator<H>) Creator.create(newHandlerClazz);
}
}

View File

@@ -0,0 +1,20 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import org.redkale.net.Filter;
/**
* HTTP 过滤器 <br>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public abstract class HttpFilter extends Filter<HttpContext, HttpRequest, HttpResponse> {
}

View File

@@ -0,0 +1,85 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 配合 HttpServlet 使用。
* 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface HttpMapping {
/**
* 操作ID值鉴权时用到
*
* @return int
*/
int actionid() default 0;
String url();
/**
* 结果缓存的秒数, 为0表示不缓存 <br>
* * 当值大于0将被缓存一段时间(默认值 seconds=15秒)。 <br>
* 通常情况下需要 auth() == true 才使用没有标记auth==true方法一般输出的结果与当前用户信息有关。 <br>
*
* @return int
*/
int cacheseconds() default 0;
/**
* 是否鉴权,默认需要鉴权 <br>
*
* @return boolean
*/
boolean auth() default true;
/**
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法
*
* @return String[]
*/
String[] methods() default {};
/**
* 是否能被继承, 当 HttpServlet 被继承后该方法是否能被子类继承
*
* @return boolean
*/
boolean inherited() default true;
/**
* 输出结果的数据类型
*
* @return String
*/
String result() default "Object";
/**
* 输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
*
* @return Class[]
*/
Class[] results() default {};
/**
* 备注描述
*
* @return String
*/
String comment() default "";
}

View File

@@ -0,0 +1,61 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 配合 &#64;HttpMapping 使用。
* 用于对&#64;HttpMapping方法中参数描述
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Repeatable(HttpParam.HttpParams.class)
public @interface HttpParam {
String name(); //参数名
Class type(); //参数的数据类型
String comment() default ""; //备注描述
HttpParamSourceType src() default HttpParamSourceType.PARAMETER; //参数来源类型
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
boolean required() default true; //参数是否必传
/**
* 配合 &#64;HttpParam 使用。
* 用于对&#64;HttpParam中参数的来源类型
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public static enum HttpParamSourceType {
PARAMETER, HEADER, COOKIE;
}
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@interface HttpParams {
HttpParam[] value();
}
}

View File

@@ -8,15 +8,17 @@ package org.redkale.net.http;
import org.redkale.util.AnyValue.DefaultAnyValue;
import java.io.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.function.*;
import java.util.logging.*;
import java.util.regex.*;
import org.redkale.net.*;
import org.redkale.net.http.Rest.RestDynSourceType;
import org.redkale.service.Service;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
* HTTP Servlet的总入口请求在HttpPrepareServlet中进行分流。 <br>
* 一个HttpServer只有一个HttpPrepareServlet 用于管理所有HttpServlet。 <br>
*
* <p>
* 详情见: https://redkale.org
@@ -27,28 +29,180 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
protected SimpleEntry<Predicate<String>, HttpServlet>[] regArray = new SimpleEntry[0];
protected HttpServlet resourceHttpServlet = new HttpResourceServlet();
protected MappingEntry[] regArray = null; //regArray 包含 regWsArray
protected MappingEntry[] regWsArray = null;
protected Map<String, WebSocketServlet> wsmappings = new HashMap<>(); //super.mappings 包含 wsmappings
protected final Map<String, Class> allMapStrings = new HashMap<>();
private final Object excludeLock = new Object();
private Map<String, BiPredicate<String, String>> forbidURIMaps; //禁用的URL的正则表达式, 必须与 forbidURIPredicates 保持一致
private BiPredicate<String, String>[] forbidURIPredicates; //禁用的URL的Predicate, 必须与 forbidURIMaps 保持一致
private List<HttpServlet> removeHttpServlet(final Predicate<MappingEntry> predicateEntry, final Predicate<Map.Entry<String, WebSocketServlet>> predicateFilter) {
List<HttpServlet> servlets = new ArrayList<>();
synchronized (allMapStrings) {
List<String> keys = new ArrayList<>();
if (regArray != null) {
for (MappingEntry me : regArray) {
if (predicateEntry.test(me)) {
servlets.add(me.servlet);
keys.add(me.mapping);
}
}
}
if (regWsArray != null) {
for (MappingEntry me : regWsArray) {
if (predicateEntry.test(me)) {
servlets.add(me.servlet);
keys.add(me.mapping);
}
}
}
Map<String, WebSocketServlet> newwsmappings = new HashMap<>();
for (Map.Entry<String, WebSocketServlet> en : wsmappings.entrySet()) {
if (predicateFilter.test(en)) {
servlets.add(en.getValue());
keys.add(en.getKey());
} else {
newwsmappings.put(en.getKey(), en.getValue());
}
}
if (newwsmappings.size() != wsmappings.size()) this.wsmappings = newwsmappings;
if (!keys.isEmpty()) {
this.regArray = Utility.remove(this.regArray, predicateEntry);
this.regWsArray = Utility.remove(this.regWsArray, predicateEntry);
for (HttpServlet rs : servlets) {
super.removeServlet(rs);
}
for (String key : keys) {
super.removeMapping(key);
allMapStrings.remove(key);
}
}
}
return servlets;
}
public HttpServlet removeHttpServlet(final HttpServlet servlet) {
Predicate<MappingEntry> predicateEntry = (t) -> t.servlet == servlet;
Predicate<Map.Entry<String, WebSocketServlet>> predicateFilter = (t) -> t.getValue() == servlet;
removeHttpServlet(predicateEntry, predicateFilter);
return servlet;
}
public <T extends HttpServlet> HttpServlet removeHttpServlet(Service service) {
Predicate<MappingEntry> predicateEntry = (t) -> {
if (!Rest.isRestDyn(t.servlet)) return false;
Service s = Rest.getService(t.servlet);
if (s == service) return true;
if (s != null) return false;
Map<String, Service> map = Rest.getServiceMap(t.servlet);
if (map == null) return false;
boolean rs = map.values().contains(service);
if (rs && map.size() == 1) return true;
if (rs && map.size() > 1) {
String key = null;
for (Map.Entry<String, Service> en : map.entrySet()) {
if (en.getValue() == service) {
key = en.getKey();
break;
}
}
if (key != null) map.remove(key);
return false; //还有其他Resouce.name 的Service
}
return rs;
};
Predicate<Map.Entry<String, WebSocketServlet>> predicateFilter = null;
List<HttpServlet> list = removeHttpServlet(predicateEntry, predicateFilter);
return list == null || list.isEmpty() ? null : list.get(0);
}
public <T extends WebSocket> HttpServlet removeHttpServlet(Class<T> websocketOrServletType) {
Predicate<MappingEntry> predicateEntry = (t) -> {
Class type = t.servlet.getClass();
if (type == websocketOrServletType) return true;
RestDynSourceType rdt = (RestDynSourceType) type.getAnnotation(RestDynSourceType.class);
return (rdt != null && rdt.value() == websocketOrServletType);
};
Predicate<Map.Entry<String, WebSocketServlet>> predicateFilter = (t) -> {
Class type = t.getValue().getClass();
if (type == websocketOrServletType) return true;
RestDynSourceType rdt = (RestDynSourceType) type.getAnnotation(RestDynSourceType.class);
return (rdt != null && rdt.value() == websocketOrServletType);
};
List<HttpServlet> list = removeHttpServlet(predicateEntry, predicateFilter);
return list == null || list.isEmpty() ? null : list.get(0);
}
public boolean addForbidURIReg(final String urlreg) {
if (urlreg == null || urlreg.isEmpty()) return false;
synchronized (excludeLock) {
if (forbidURIMaps != null && forbidURIMaps.containsKey(urlreg)) return false;
if (forbidURIMaps == null) forbidURIMaps = new HashMap<>();
String mapping = urlreg;
if (Utility.contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
if (mapping.endsWith("/*")) {
mapping = mapping.substring(0, mapping.length() - 1) + ".*";
} else {
mapping = mapping + "$";
}
}
final String reg = mapping;
final boolean begin = mapping.charAt(0) == '^';
final Predicate regPredicate = Pattern.compile(reg).asPredicate();
BiPredicate<String, String> predicate = (prefix, uri) -> {
return begin || prefix.isEmpty() ? regPredicate.test(uri) : uri.matches(prefix + reg);
};
forbidURIMaps.put(urlreg, predicate);
forbidURIPredicates = Utility.append(forbidURIPredicates, predicate);
return true;
}
}
public boolean removeForbidURIReg(final String urlreg) {
if (urlreg == null || urlreg.isEmpty()) return false;
synchronized (excludeLock) {
if (forbidURIMaps == null || forbidURIPredicates == null || !forbidURIMaps.containsKey(urlreg)) return false;
BiPredicate<String, String> predicate = forbidURIMaps.get(urlreg);
forbidURIMaps.remove(urlreg);
int index = -1;
for (int i = 0; i < forbidURIPredicates.length; i++) {
if (forbidURIPredicates[i] == predicate) {
index = i;
break;
}
}
if (index > -1) {
if (forbidURIPredicates.length == 1) {
forbidURIPredicates = null;
} else {
int newlen = forbidURIPredicates.length - 1;
BiPredicate[] news = new BiPredicate[newlen];
System.arraycopy(forbidURIPredicates, 0, news, 0, index);
System.arraycopy(forbidURIPredicates, index + 1, news, index, newlen - index);
forbidURIPredicates = news;
}
}
return true;
}
}
@Override
public void init(HttpContext context, AnyValue config) {
this.servlets.forEach(s -> {
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).preInit(context, getServletConf(s));
} else if (s instanceof HttpBaseServlet) {
((HttpBaseServlet) s).preInit(context, getServletConf(s));
}
super.init(context, config); //必须要执行
Collection<HttpServlet> servlets = getServlets();
servlets.forEach(s -> {
s.preInit(context, getServletConf(s));
s.init(context, getServletConf(s));
});
final WatchFactory watch = context.getWatchFactory();
if (watch != null) {
this.servlets.forEach(s -> {
watch.inject(s);
});
}
AnyValue resConfig = config.getAnyValue("resource-servlet");
if ((resConfig instanceof DefaultAnyValue) && resConfig.getValue("webroot", "").isEmpty()) {
((DefaultAnyValue) resConfig).addValue("webroot", config.getValue("root"));
@@ -69,7 +223,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
String resServlet = resConfig.getValue("servlet", HttpResourceServlet.class.getName());
try {
this.resourceHttpServlet = (HttpServlet) Class.forName(resServlet).newInstance();
} catch (Exception e) {
} catch (Throwable e) {
this.resourceHttpServlet = new HttpResourceServlet();
logger.log(Level.WARNING, "init HttpResourceSerlvet(" + resServlet + ") error", e);
}
@@ -80,16 +234,48 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
public void execute(HttpRequest request, HttpResponse response) throws IOException {
try {
final String uri = request.getRequestURI();
Servlet<HttpContext, HttpRequest, HttpResponse> servlet = this.mappings.isEmpty() ? null : this.mappings.get(uri);
if (servlet == null && this.regArray != null) {
for (SimpleEntry<Predicate<String>, HttpServlet> en : regArray) {
if (en.getKey().test(uri)) {
servlet = en.getValue();
HttpServlet servlet;
if (request.isWebSocket()) {
servlet = wsmappings.get(uri);
if (servlet == null && this.regWsArray != null) {
for (MappingEntry en : regWsArray) {
if (en.predicate.test(uri)) {
servlet = en.servlet;
break;
}
}
}
if (servlet == null) {
response.finish(500, null);
return;
}
} else {
servlet = mappingServlet(uri);
if (servlet == null && this.regArray != null) {
for (MappingEntry en : regArray) {
if (en.predicate.test(uri)) {
servlet = en.servlet;
break;
}
}
}
//找不到匹配的HttpServlet则使用静态资源HttpResourceServlet
if (servlet == null) servlet = this.resourceHttpServlet;
}
boolean forbid = false;
BiPredicate<String, String>[] forbidUrlPredicates = this.forbidURIPredicates;
if (forbidUrlPredicates != null && forbidUrlPredicates.length > 0) {
for (BiPredicate<String, String> predicate : forbidUrlPredicates) {
if (predicate != null && predicate.test(servlet._prefix, uri)) {
forbid = true;
break;
}
}
}
if (servlet == null) servlet = this.resourceHttpServlet;
if (forbid) {
response.finish(403, response.getHttpCode(403));
return;
}
servlet.execute(request, response);
} catch (Exception e) {
request.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
@@ -97,6 +283,14 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
}
}
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param prefix url前缀
* @param conf 配置信息
* @param mappings 匹配规则
*/
@Override
public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) {
if (prefix == null) prefix = "";
@@ -107,12 +301,12 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix
}
}
synchronized (allMapStrings) {
synchronized (allMapStrings) { //需要整段锁住
for (String mapping : mappings) {
if (mapping == null) continue;
if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
if (contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
if (Utility.contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
if (mapping.charAt(0) != '^') mapping = '^' + mapping;
if (mapping.endsWith("/*")) {
mapping = mapping.substring(0, mapping.length() - 1) + ".*";
@@ -120,14 +314,28 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
mapping = mapping + "$";
}
if (regArray == null) {
regArray = new SimpleEntry[1];
regArray[0] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
regArray = new MappingEntry[1];
regArray[0] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), servlet);
} else {
regArray = Arrays.copyOf(regArray, regArray.length + 1);
regArray[regArray.length - 1] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
regArray[regArray.length - 1] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), servlet);
}
if (servlet instanceof WebSocketServlet) {
if (regWsArray == null) {
regWsArray = new MappingEntry[1];
regWsArray[0] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), (WebSocketServlet) servlet);
} else {
regWsArray = Arrays.copyOf(regWsArray, regWsArray.length + 1);
regWsArray[regWsArray.length - 1] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), (WebSocketServlet) servlet);
}
}
} else if (mapping != null && !mapping.isEmpty()) {
super.mappings.put(mapping, servlet);
putMapping(mapping, servlet);
if (servlet instanceof WebSocketServlet) {
Map<String, WebSocketServlet> newmappings = new HashMap<>(wsmappings);
newmappings.put(mapping, (WebSocketServlet) servlet);
this.wsmappings = newmappings;
}
}
if (this.allMapStrings.containsKey(mapping)) {
Class old = this.allMapStrings.get(mapping);
@@ -137,42 +345,57 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
}
setServletConf(servlet, conf);
servlet._prefix = prefix.toString();
this.servlets.add(servlet);
putServlet(servlet);
}
}
private static boolean contains(String string, char... values) {
if (string == null) return false;
for (char ch : Utility.charArray(string)) {
for (char ch2 : values) {
if (ch == ch2) return true;
}
}
return false;
}
/**
* 设置静态资源HttpServlet
*
* @param servlet HttpServlet
*/
public void setResourceServlet(HttpServlet servlet) {
if (servlet != null) {
this.resourceHttpServlet = servlet;
}
}
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() {
return this.resourceHttpServlet;
}
@Override
public void destroy(HttpContext context, AnyValue config) {
super.destroy(context, config); //必须要执行
this.resourceHttpServlet.destroy(context, config);
this.servlets.forEach(s -> {
getServlets().forEach(s -> {
s.destroy(context, getServletConf(s));
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).postDestroy(context, getServletConf(s));
} else if (s instanceof HttpBaseServlet) {
((HttpBaseServlet) s).postDestroy(context, getServletConf(s));
}
s.postDestroy(context, getServletConf(s));
});
this.allMapStrings.clear();
this.wsmappings.clear();
this.regArray = null;
this.regWsArray = null;
}
protected static class MappingEntry {
public final String mapping;
public final Predicate<String> predicate;
public final HttpServlet servlet;
public MappingEntry(String mapping, Predicate<String> predicate, HttpServlet servlet) {
this.mapping = mapping;
this.predicate = predicate;
this.servlet = servlet;
}
}
}

View File

@@ -12,8 +12,8 @@ import java.nio.channels.Channels;
import java.nio.charset.Charset;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*;
import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.ByteArray;
/**
* Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。 <br>
@@ -22,7 +22,7 @@ import org.redkale.util.ByteArray;
* 例如简单的翻页查询 <br>
* /pipes/record/query/offset:0/limit:20 <br>
* 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br>
* 获取行数: int limit = request.getRequstURIPath("limit:", 10);
* 获取行数: int limit = request.getRequstURIPath("limit:", 10); <br>
* <p>
* 详情见: https://redkale.org
*
@@ -34,6 +34,7 @@ public class HttpRequest extends Request<HttpContext> {
protected static final String SESSIONID_NAME = "JSESSIONID";
@Comment("Method GET/POST/...")
private String method;
private String protocol;
@@ -48,7 +49,8 @@ public class HttpRequest extends Request<HttpContext> {
private String connection;
protected String cookiestr;
@Comment("原始的cookie字符串解析后值赋给HttpCookie[] cookies")
protected String cookie;
private HttpCookie[] cookies;
@@ -64,13 +66,25 @@ public class HttpRequest extends Request<HttpContext> {
protected boolean boundary = false;
protected int moduleid;
protected int actionid;
protected Object currentUser;
private final String remoteAddrHeader;
Object attachment; //仅供HttpServlet传递Entry使用
public HttpRequest(HttpContext context, String remoteAddrHeader) {
super(context);
this.remoteAddrHeader = remoteAddrHeader;
}
protected boolean isWebSocket() {
return connection != null && connection.contains("Upgrade") && "GET".equalsIgnoreCase(method) && "websocket".equalsIgnoreCase(getHeader("Upgrade"));
}
protected void setKeepAlive(boolean keepAlive) {
this.keepAlive = keepAlive;
}
@@ -129,10 +143,10 @@ public class HttpRequest extends Request<HttpContext> {
this.host = value;
break;
case "Cookie":
if (this.cookiestr == null || this.cookiestr.isEmpty()) {
this.cookiestr = value;
if (this.cookie == null || this.cookie.isEmpty()) {
this.cookie = value;
} else {
this.cookiestr += ";" + value;
this.cookie += ";" + value;
}
break;
case "Connection":
@@ -230,6 +244,51 @@ public class HttpRequest extends Request<HttpContext> {
return super.removeProperty(name);
}
/**
* 设置当前用户信息, 通常在HttpServlet.preExecute方法里设置currentUser <br>
* 数据类型由&#64;HttpUserType指定
*
* @param <T> 泛型
* @param user 用户信息
*
* @return HttpRequest
*/
public <T> HttpRequest setCurrentUser(T user) {
this.currentUser = user;
return this;
}
/**
* 获取当前用户信息<br>
* 数据类型由&#64;HttpUserType指定
*
* @param <T> &#64;HttpUserType指定的用户信息类型
*
* @return 用户信息
*/
@SuppressWarnings("unchecked")
public <T> T currentUser() {
return (T) this.currentUser;
}
/**
* 获取模块ID来自&#64;HttpServlet.moduleid()
*
* @return 模块ID
*/
public int getModuleid() {
return this.moduleid;
}
/**
* 获取操作ID来自&#64;HttpMapping.actionid()
*
* @return 模块ID
*/
public int getActionid() {
return this.actionid;
}
/**
* 获取客户端地址IP
*
@@ -276,6 +335,44 @@ public class HttpRequest extends Request<HttpContext> {
return array.toString(UTF8);
}
/**
* 获取请求内容的JavaBean对象
*
* @param <T> 泛型
* @param type 类型
*
* @return 内容
*/
public <T> T getBodyJson(java.lang.reflect.Type type) {
String str = array.toString(UTF8);
if (str == null || str.isEmpty()) return null;
return context.getJsonConvert().convertFrom(type, str);
}
/**
* 获取请求内容的JavaBean对象
*
* @param <T> 泛型
* @param convert JsonConvert
* @param type 类型
*
* @return 内容
*/
public <T> T getBodyJson(JsonConvert convert, java.lang.reflect.Type type) {
String str = array.toString(UTF8);
if (str == null || str.isEmpty()) return null;
return convert.convertFrom(type, str);
}
/**
* 获取请求内容的byte[]
*
* @return 内容
*/
public byte[] getBody() {
return array.getBytes();
}
/**
* 直接获取body对象
*
@@ -289,7 +386,7 @@ public class HttpRequest extends Request<HttpContext> {
public String toString() {
parseBody();
return this.getClass().getSimpleName() + "{\r\n method: " + this.method + ", \r\n requestURI: " + this.requestURI
+ ", \r\n remoteAddr: " + this.getRemoteAddr() + ", \r\n cookies: " + this.cookiestr + ", \r\n contentType: " + this.contentType
+ ", \r\n remoteAddr: " + this.getRemoteAddr() + ", \r\n cookies: " + this.cookie + ", \r\n contentType: " + this.contentType
+ ", \r\n connection: " + this.connection + ", \r\n protocol: " + this.protocol + ", \r\n host: " + this.host
+ ", \r\n contentLength: " + this.contentLength + ", \r\n bodyLength: " + this.array.size() + (this.boundary || this.array.isEmpty() ? "" : (", \r\n bodyContent: " + this.getBodyUTF8()))
+ ", \r\n params: " + this.params.toString(4) + ", \r\n header: " + this.header.toString(4) + "\r\n}";
@@ -323,7 +420,7 @@ public class HttpRequest extends Request<HttpContext> {
@Override
protected void recycle() {
this.cookiestr = null;
this.cookie = null;
this.cookies = null;
this.newsessionid = null;
this.method = null;
@@ -335,6 +432,11 @@ public class HttpRequest extends Request<HttpContext> {
this.contentLength = -1;
this.boundary = false;
this.bodyparsed = false;
this.moduleid = 0;
this.actionid = 0;
this.currentUser = null;
this.attachment = null;
this.header.clear();
this.params.clear();
@@ -352,7 +454,7 @@ public class HttpRequest extends Request<HttpContext> {
public String getSessionid(boolean create) {
String sessionid = getCookie(SESSIONID_NAME, null);
if (create && (sessionid == null || sessionid.isEmpty())) {
sessionid = ((HttpContext) context).createSessionid();
sessionid = context.createSessionid();
this.newsessionid = sessionid;
}
return sessionid;
@@ -368,6 +470,18 @@ public class HttpRequest extends Request<HttpContext> {
return newsessionid;
}
/**
* 指定值更新sessionid
*
* @param newsessionid 新sessionid值
*
* @return 新的sessionid值
*/
public String changeSessionid(String newsessionid) {
this.newsessionid = newsessionid == null ? context.createSessionid() : newsessionid.trim();
return newsessionid;
}
/**
* 使sessionid失效
*/
@@ -381,7 +495,7 @@ public class HttpRequest extends Request<HttpContext> {
* @return cookie对象数组
*/
public HttpCookie[] getCookies() {
if (this.cookies == null) this.cookies = parseCookies(this.cookiestr);
if (this.cookies == null) this.cookies = parseCookies(this.cookie);
return this.cookies;
}
@@ -500,6 +614,123 @@ public class HttpRequest extends Request<HttpContext> {
return requestURI.substring(requestURI.lastIndexOf('/') + 1);
}
/**
* 获取请求URL最后的一个/后面的部分的short值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2
*
* @param defvalue 默认short值
*
* @return short值
*/
public short getRequstURILastPath(short defvalue) {
String val = getRequstURILastPath();
if (val.isEmpty()) return defvalue;
return val.isEmpty() ? defvalue : Short.parseShort(val);
}
/**
* 获取请求URL最后的一个/后面的部分的short值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: short type = request.getRequstURILastPath(16, (short)0); //type = 2
*
* @param radix 进制数
* @param defvalue 默认short值
*
* @return short值
*/
public short getRequstURILastPath(int radix, short defvalue) {
String val = getRequstURILastPath();
if (val.isEmpty()) return defvalue;
return val.isEmpty() ? defvalue : Short.parseShort(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: int type = request.getRequstURILastPath(0); //type = 2
*
* @param defvalue 默认int值
*
* @return int值
*/
public int getRequstURILastPath(int defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Integer.parseInt(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: int type = request.getRequstURILastPath(16, 0); //type = 2
*
* @param radix 进制数
* @param defvalue 默认int值
*
* @return int值
*/
public int getRequstURILastPath(int radix, int defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Integer.parseInt(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的float值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: float type = request.getRequstURILastPath(0.0f); //type = 2.0f
*
* @param defvalue 默认float值
*
* @return float值
*/
public float getRequstURILastPath(float defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Float.parseFloat(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2
*
* @param defvalue 默认long值
*
* @return long值
*/
public long getRequstURILastPath(long defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Long.parseLong(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: long type = request.getRequstURILastPath(16, 0L); //type = 2
*
* @param radix 进制数
* @param defvalue 默认long值
*
* @return long值
*/
public long getRequstURILastPath(int radix, long defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Long.parseLong(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的double值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0
*
* @param defvalue 默认double值
*
* @return double值
*/
public double getRequstURILastPath(double defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Double.parseDouble(val);
}
/**
*
* 从prefix之后截取getRequestURI再对"/"进行分隔
@@ -1109,17 +1340,18 @@ public class HttpRequest extends Request<HttpContext> {
* @return Flipper翻页对象
*/
public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) {
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name);
if (flipper == null) {
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
int limit = getRequstURIPath("limit:", maxLimit);
int offset = getRequstURIPath("offset:", 0);
String sort = getRequstURIPath("sort:", "");
if (limit > 0) flipper = new org.redkale.source.Flipper(limit, offset, sort);
} else if (flipper.getLimit() < 1 || flipper.getLimit() > maxLimit) {
} else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) {
flipper.setLimit(maxLimit);
}
if (flipper != null || !needcreate) return flipper;
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
return new org.redkale.source.Flipper(maxLimit);
}
}

View File

@@ -18,6 +18,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue;
/**
* 静态资源HttpServlet
*
* <p>
* 详情见: https://redkale.org
@@ -268,7 +269,7 @@ public class HttpResourceServlet extends HttpServlet {
public void update() {
if (this.file == null) return;
if (this.content != null) {
if (this.content != null) {
this.servlet.cachedLength.add(0L - this.content.remaining());
this.content = null;
}

View File

@@ -13,7 +13,9 @@ import java.nio.channels.*;
import java.nio.file.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
@@ -21,9 +23,9 @@ import org.redkale.util.AnyValue.Entry;
import org.redkale.util.*;
/**
* Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。
* 同时提供发送json的系列接口: public void finishJson(Type type, Object obj)
* Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。
* Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。 <br>
* 同时提供发送json的系列接口: public void finishJson(Type type, Object obj) <br>
* Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。 <br>
* <p>
* 详情见: https://redkale.org
*
@@ -46,6 +48,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
protected static final byte[] LINE = new byte[]{'\r', '\n'};
protected static final byte[] serverNameBytes = ("Server: redkale/" + Redkale.getDotedVersion() + "\r\n").getBytes();
private static final Set<OpenOption> options = new HashSet<>();
private static final DateFormat GMT_DATE_FORMAT = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss z", Locale.ENGLISH);
@@ -176,6 +180,11 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
return v == null ? defValue : v;
}
@Override
protected void thenEvent(Servlet servlet) {
this.servlet = servlet;
}
/**
* 增加Cookie值
*
@@ -200,6 +209,41 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
return this;
}
/**
* 创建AsyncHandler实例
*
* @return AsyncHandler
*/
public AsyncHandler createAsyncHandler() {
return AsyncHandler.create((v, a) -> {
if (v instanceof org.redkale.service.RetResult) {
finishJson((org.redkale.service.RetResult) v);
} else if (v instanceof CharSequence) {
finish(String.valueOf(v));
} else {
finishJson(v);
}
}, (t, a) -> {
request.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, t);
finish(500, null);
});
}
/**
* 创建AsyncHandler子类的实例 <br>
*
* 传入的AsyncHandler子类必须是public且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
*
* @param <H> 泛型
* @param handlerClass AsyncHandler子类
*
* @return AsyncHandler AsyncHandler
*/
public <H extends AsyncHandler> H createAsyncHandler(Class<H> handlerClass) {
if (handlerClass == null || handlerClass == AsyncHandler.class) return (H) createAsyncHandler();
return context.loadAsyncHandlerCreator(handlerClass).create(createAsyncHandler());
}
/**
* 将对象以JSON格式输出
*
@@ -291,28 +335,99 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
}
/**
* 将对象以JavaScript格式输出
* 将CompletableFuture的结果对象以JSON格式输出
*
* @param var js变量名
* @param result 输出对象
* @param future 输出对象的句柄
*/
public void finishJsResult(String var, Object result) {
this.contentType = "application/javascript; charset=utf-8";
if (this.recycleListener != null) this.output = result;
finish("var " + var + " = " + request.getJsonConvert().convertTo(result) + ";");
public void finishJson(final CompletableFuture future) {
finishJson(request.getJsonConvert(), future);
}
/**
* 将对象以JavaScript格式输出
* 将CompletableFuture的结果对象以JSON格式输出
*
* @param jsonConvert 指定的JsonConvert
* @param var js变量名
* @param result 输出对象
* @param convert 指定的JsonConvert
* @param future 输出对象的句柄
*/
public void finishJsResult(JsonConvert jsonConvert, String var, Object result) {
this.contentType = "application/javascript; charset=utf-8";
if (this.recycleListener != null) this.output = result;
finish("var " + var + " = " + jsonConvert.convertTo(result) + ";");
public void finishJson(final JsonConvert convert, final CompletableFuture future) {
future.whenComplete((v, e) -> {
if (e != null) {
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
finish(500, null);
return;
}
if (v instanceof CharSequence) {
finish(v.toString());
} else if (v instanceof org.redkale.service.RetResult) {
finishJson(convert, (org.redkale.service.RetResult) v);
} else {
finishJson(convert, v);
}
});
}
/**
* 将CompletableFuture的结果对象以JSON格式输出
*
* @param convert 指定的JsonConvert
* @param type 指定的类型
* @param future 输出对象的句柄
*/
public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future) {
future.whenComplete((v, e) -> {
if (e != null) {
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
finish(500, null);
return;
}
if (v instanceof CharSequence) {
finish(v.toString());
} else if (v instanceof HttpResult) {
finishJson(convert, (HttpResult) v);
} else if (v instanceof org.redkale.service.RetResult) {
finishJson(convert, (org.redkale.service.RetResult) v);
} else {
finishJson(convert, type, v);
}
});
}
/**
* 将HttpResult的结果对象以JSON格式输出
*
* @param result HttpResult对象
*/
public void finishJson(final HttpResult result) {
finishJson(request.getJsonConvert(), result);
}
/**
* 将HttpResult的结果对象以JSON格式输出
*
* @param convert 指定的JsonConvert
* @param result HttpResult对象
*/
public void finishJson(final JsonConvert convert, final HttpResult result) {
if (output == null) {
finish("");
return;
}
if (result.getContentType() != null) setContentType(result.getContentType());
addHeader(result.getHeaders()).addCookie(result.getCookies()).setStatus(result.getStatus() < 1 ? 200 : result.getStatus());
if (result.getResult() instanceof File) {
try {
finish((File) result.getResult());
} catch (IOException e) {
getContext().getLogger().log(Level.WARNING, "HttpServlet finishJson HttpResult File occur, forece to close channel. request = " + getRequest(), e);
finish(500, null);
}
} else if (result.getResult() instanceof String) {
finish((String) result.getResult());
} else if (result.getResult() == null) {
finish(result.getMessage());
} else {
finishJson(result.getResult());
}
}
/**
@@ -321,6 +436,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param obj 输出内容
*/
public void finish(String obj) {
if (isClosed()) return;
if (this.recycleListener != null) this.output = obj;
if (obj == null || obj.isEmpty()) {
final ByteBuffer headbuf = createHeader();
@@ -362,6 +478,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param message 输出内容
*/
public void finish(int status, String message) {
if (isClosed()) return;
this.status = status;
if (status != 200) super.refuseAlive();
finish(message);
@@ -381,6 +498,24 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
super.finish(buffer404.duplicate());
}
/**
* 将指定byte[]按响应结果输出
*
* @param bs 输出内容
*/
@Override
public void finish(final byte[] bs) {
if (isClosed()) return; //避免重复关闭
if (this.context.getBufferCapacity() == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
buffer.flip();
this.finish(false, buffer);
} else {
this.finish(false, ByteBuffer.wrap(bs));
}
}
/**
* 将指定ByteBuffer按响应结果输出
*
@@ -399,6 +534,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/
@Override
public void finish(boolean kill, ByteBuffer buffer) {
if (isClosed()) return; //避免重复关闭
if (!this.headsended) {
this.contentLength = buffer == null ? 0 : buffer.remaining();
ByteBuffer headbuf = createHeader();
@@ -431,6 +567,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/
@Override
public void finish(boolean kill, ByteBuffer... buffers) {
if (isClosed()) return; //避免重复关闭
if (bufferHandler != null) {
ByteBuffer[] bufs = bufferHandler.execute(this, buffers);
if (bufs != null) buffers = bufs;
@@ -465,7 +602,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param attachment 异步回调参数
* @param handler 异步回调函数
*/
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler) {
public <A> void sendBody(ByteBuffer buffer, A attachment, AsyncHandler<Integer, A> handler) {
if (!this.headsended) {
if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining();
ByteBuffer headbuf = createHeader();
@@ -480,6 +617,37 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
}
}
/**
* 异步输出指定内容
*
* @param <A> 泛型
* @param buffers 输出内容
* @param attachment 异步回调参数
* @param handler 异步回调函数
*/
public <A> void sendBody(ByteBuffer[] buffers, A attachment, AsyncHandler<Integer, A> handler) {
if (!this.headsended) {
if (this.contentLength < 0) {
int len = 0;
if (buffers != null && buffers.length > 0) {
for (ByteBuffer b : buffers) {
len += b.remaining();
}
}
this.contentLength = len;
}
ByteBuffer headbuf = createHeader();
headbuf.flip();
if (buffers == null || buffers.length == 0) {
super.send(headbuf, attachment, handler);
} else {
super.send(Utility.unshift(buffers, headbuf), attachment, handler);
}
} else {
super.send(buffers, attachment, handler);
}
}
/**
* 将指定文件按响应结果输出
*
@@ -592,6 +760,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
if (!this.request.isKeepAlive()) {
buffer.put("Connection: close\r\n".getBytes());
}
buffer.put(serverNameBytes);
if (this.defaultAddHeaders != null) {
for (String[] headers : this.defaultAddHeaders) {
if (headers.length > 3) {
@@ -804,7 +974,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
this.bufferHandler = bufferHandler;
}
protected final class TransferFileHandler implements CompletionHandler<Integer, ByteBuffer> {
protected final class TransferFileHandler implements AsyncHandler<Integer, ByteBuffer> {
private final AsynchronousFileChannel filechannel;

View File

@@ -0,0 +1,128 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import java.io.Serializable;
import java.net.HttpCookie;
import java.util.*;
import org.redkale.convert.json.JsonConvert;
/**
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 结果对象的类型
*/
public class HttpResult<T> {
public static final String SESSIONID_COOKIENAME = HttpRequest.SESSIONID_NAME;
private Map<String, String> headers;
private List<HttpCookie> cookies;
private String contentType;
private T result;
private int status = 0; //不设置则为 200
private String message;
public HttpResult() {
}
public HttpResult(T result) {
this.result = result;
}
public HttpResult<T> header(String name, Serializable value) {
if (this.headers == null) this.headers = new HashMap<>();
this.headers.put(name, String.valueOf(value));
return this;
}
public HttpResult<T> cookie(HttpCookie cookie) {
if (this.cookies == null) this.cookies = new ArrayList<>();
this.cookies.add(cookie);
return this;
}
public HttpResult<T> contentType(String contentType) {
this.contentType = contentType;
return this;
}
public HttpResult<T> result(T result) {
this.result = result;
return this;
}
public HttpResult<T> status(int status) {
this.status = status;
return this;
}
public HttpResult<T> message(String message) {
this.message = message;
return this;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public List<HttpCookie> getCookies() {
return cookies;
}
public void setCookies(List<HttpCookie> cookies) {
this.cookies = cookies;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}

View File

@@ -11,25 +11,26 @@ import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import org.redkale.net.*;
import org.redkale.net.sncp.Sncp;
import org.redkale.service.Service;
import org.redkale.util.*;
import org.redkale.watch.WatchFactory;
/**
* Http服务器
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public final class HttpServer extends Server<String, HttpContext, HttpRequest, HttpResponse, HttpServlet> {
public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpResponse, HttpServlet> {
public HttpServer() {
this(System.currentTimeMillis(), null);
this(System.currentTimeMillis());
}
public HttpServer(long serverStartTime, final WatchFactory watch) {
super(serverStartTime, "TCP", new HttpPrepareServlet(), watch);
public HttpServer(long serverStartTime) {
super(serverStartTime, "TCP", new HttpPrepareServlet());
}
@Override
@@ -37,34 +38,196 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
super.init(config);
}
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() {
return ((HttpPrepareServlet) this.prepare).resourceHttpServlet;
}
/**
* 删除HttpFilter
*
* @param filterName HttpFilter名称
*
* @return HttpFilter
*/
public HttpFilter removeFilter(String filterName) {
return (HttpFilter) this.prepare.removeFilter(filterName);
}
/**
* 删除HttpServlet
*
* @param service Service
*
* @return HttpServlet
*/
public HttpServlet removeHttpServlet(Service service) {
return ((HttpPrepareServlet) this.prepare).removeHttpServlet(service);
}
/**
* 删除HttpServlet
*
* @param <T> 泛型
* @param websocketOrServletType Class
*
* @return HttpServlet
*/
public <T extends WebSocket> HttpServlet removeHttpServlet(Class<T> websocketOrServletType) {
return ((HttpPrepareServlet) this.prepare).removeHttpServlet(websocketOrServletType);
}
/**
* 屏蔽请求URL的正则表达式
*
* @param urlreg 正则表达式
*
* @return 是否成功
*/
public boolean addForbidURIReg(final String urlreg) {
return ((HttpPrepareServlet) this.prepare).addForbidURIReg(urlreg);
}
/**
* 删除屏蔽请求URL的正则表达式
*
* @param urlreg 正则表达式
*
* @return 是否成功
*/
public boolean removeForbidURIReg(final String urlreg) {
return ((HttpPrepareServlet) this.prepare).removeForbidURIReg(urlreg);
}
/**
* 删除HttpFilter
*
* @param <T> 泛型
* @param filterClass HttpFilter类
*
* @return HttpFilter
*/
public <T extends HttpFilter> T removeFilter(Class<T> filterClass) {
return (T) this.prepare.removeFilter(filterClass);
}
/**
* 添加HttpFilter
*
* @param filter HttpFilter
* @param conf AnyValue
*
* @return HttpServer
*/
public HttpServer addHttpFilter(HttpFilter filter, AnyValue conf) {
this.prepare.addFilter(filter, conf);
return this;
}
/**
* 添加HttpServlet
*
* @param prefix url前缀
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, prefix, null, mappings);
return this;
}
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, null, null, mappings);
return this;
}
public void addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) {
/**
* 添加HttpServlet
*
* @param prefix url前缀
* @param servlet HttpServlet
* @param conf 配置信息
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) {
this.prepare.addServlet(servlet, prefix, conf, mappings);
return this;
}
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(String name, Class<S> serviceType, S service, Class<T> baseServletClass, String prefix) {
return addRestServlet(name, serviceType, service, baseServletClass, prefix, null);
/**
* 添加WebSocketServlet
*
* @param <S> WebSocket
* @param <T> HttpServlet
* @param webSocketType WebSocket的类型
* @param prefix url前缀
* @param conf 配置信息
*
* @return RestServlet
*/
public <S extends WebSocket, T extends HttpServlet> T addRestWebSocketServlet(final Class<S> webSocketType, final String prefix, final AnyValue conf) {
T servlet = Rest.createRestWebSocketServlet(webSocketType);
if (servlet != null) this.prepare.addServlet(servlet, prefix, conf);
return servlet;
}
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(
final String name, Class<S> serviceType, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) {
RestHttpServlet servlet = null;
/**
* 添加RestServlet
*
* @param <S> Service
* @param <T> HttpServlet
* @param service Service对象
* @param userType 用户数据类型
* @param baseServletType RestServlet基类
* @param prefix url前缀
*
* @return RestServlet
*/
public <S extends Service, T extends HttpServlet> T addRestServlet(final S service, final Class userType, final Class<T> baseServletType, final String prefix) {
return addRestServlet(null, service, userType, baseServletType, prefix);
}
/**
* 添加RestServlet
*
* @param <S> Service
* @param <T> HttpServlet
* @param name 资源名
* @param service Service对象
* @param userType 用户数据类型
* @param baseServletType RestServlet基类
* @param prefix url前缀
*
* @return RestServlet
*/
public <S extends Service, T extends HttpServlet> T addRestServlet(final String name, final S service, final Class userType, final Class<T> baseServletType, final String prefix) {
T servlet = null;
final boolean sncp = Sncp.isSncpDyn(service);
final String resname = name == null ? (sncp ? Sncp.getResourceName(service) : "") : name;
final Class<S> serviceType = Sncp.getServiceType(service);
for (final HttpServlet item : ((HttpPrepareServlet) this.prepare).getServlets()) {
if (!(item instanceof RestHttpServlet)) continue;
if (item.getClass().getAnnotation(Rest.RestDynamic.class) == null) continue;
if (!(item instanceof HttpServlet)) continue;
if (item.getClass().getAnnotation(Rest.RestDyn.class) == null) continue;
try {
Field field = item.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
if (serviceType.equals(field.getType())) {
servlet = (RestHttpServlet) item;
servlet = (T) item;
break;
}
} catch (NoSuchFieldException | SecurityException e) {
@@ -73,7 +236,8 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
}
}
final boolean first = servlet == null;
if (servlet == null) servlet = Rest.createRestServlet(baseServletClass, serviceType);
if (servlet == null) servlet = Rest.createRestServlet(userType, baseServletType, serviceType);
if (servlet == null) return null; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
try { //若提供动态变更Service服务功能则改Rest服务无法做出相应更新
Field field = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
field.setAccessible(true);
@@ -82,21 +246,21 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
mapfield.setAccessible(true);
Service firstService = (Service) field.get(servlet);
if (name.isEmpty()) {
if (resname.isEmpty()) {
field.set(servlet, service);
firstService = service;
}
Map map = (Map) mapfield.get(servlet);
if (map == null && !name.isEmpty()) map = new HashMap();
if (map == null && !resname.isEmpty()) map = new HashMap();
if (map != null) {
map.put(name, service);
map.put(resname, service);
if (firstService != null) map.put("", firstService);
}
mapfield.set(servlet, map);
} catch (Exception e) {
throw new RuntimeException(serviceType + " generate rest servlet error", e);
}
if (first) this.prepare.addServlet(servlet, prefix, conf);
if (first) this.prepare.addServlet(servlet, prefix, sncp ? Sncp.getConf(service) : null);
return servlet;
}
@@ -104,8 +268,8 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
@SuppressWarnings("unchecked")
protected HttpContext createContext() {
final int port = this.address.getPort();
AtomicLong createBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("HTTP_" + port + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("HTTP_" + port + ".Buffer.cycleCounter");
AtomicLong createBufferCounter = new AtomicLong();
AtomicLong cycleBufferCounter = new AtomicLong();
this.bufferCapacity = Math.max(this.bufferCapacity, 16 * 1024 + 16); //兼容 HTTP 2.0;
final int rcapacity = this.bufferCapacity;
ObjectPool<ByteBuffer> bufferPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, this.bufferPoolSize,
@@ -184,11 +348,11 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
final String[][] setHeaders = defaultSetHeaders.isEmpty() ? null : defaultSetHeaders.toArray(new String[defaultSetHeaders.size()][]);
final HttpCookie defCookie = defaultCookie;
final String addrHeader = remoteAddrHeader;
AtomicLong createResponseCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("HTTP_" + port + ".Response.creatCounter");
AtomicLong cycleResponseCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("HTTP_" + port + ".Response.cycleCounter");
AtomicLong createResponseCounter = new AtomicLong();
AtomicLong cycleResponseCounter = new AtomicLong();
ObjectPool<Response> responsePool = HttpResponse.createPool(createResponseCounter, cycleResponseCounter, this.responsePoolSize, null);
HttpContext httpcontext = new HttpContext(this.serverStartTime, this.logger, executor, rcapacity, bufferPool, responsePool,
this.maxbody, this.charset, this.address, this.prepare, this.watch, this.readTimeoutSecond, this.writeTimeoutSecond);
this.maxbody, this.charset, this.address, this.prepare, this.readTimeoutSecond, this.writeTimeoutSecond);
responsePool.setCreator((Object... params) -> new HttpResponse(httpcontext, new HttpRequest(httpcontext, addrHeader), addHeaders, setHeaders, defCookie));
return httpcontext;
}

View File

@@ -5,17 +5,362 @@
*/
package org.redkale.net.http;
import org.redkale.net.Servlet;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.net.*;
import org.redkale.service.RetResult;
import org.redkale.util.*;
/**
* HTTP版的Servlet 执行顺序 execute --&#62; preExecute --&#62; authenticate --&#62; HttpMapping对应的方法
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public abstract class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse> {
public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse> {
public static final int RET_SERVER_ERROR = 1800_0001;
public static final int RET_METHOD_ERROR = 1800_0002;
String _prefix = ""; //当前HttpServlet的path前缀
private Map.Entry<String, Entry>[] mappings;
//这里不能直接使用HttpServlet会造成死循环初始化HttpServlet
private final Servlet<HttpContext, HttpRequest, HttpResponse> authSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
Entry entry = (Entry) request.attachment;
if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
return;
}
response.setBufferHandler(entry.cacheHandler);
}
entry.servlet.execute(request, response);
}
};
//preExecute运行完后执行的Servlet
private final Servlet<HttpContext, HttpRequest, HttpResponse> preSuccessServlet = new Servlet<HttpContext, HttpRequest, HttpResponse>() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
for (Map.Entry<String, Entry> en : mappings) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
request.attachment = entry;
request.moduleid = entry.moduleid;
request.actionid = entry.actionid;
if (entry.ignore) {
authSuccessServlet.execute(request, response);
} else {
response.thenEvent(authSuccessServlet);
authenticate(request, response);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
}
};
void preInit(HttpContext context, AnyValue config) {
String path = _prefix == null ? "" : _prefix;
WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load();
this.mappings = new Map.Entry[map.size()];
int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) {
mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
}
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
Arrays.sort(mappings, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
}
void postDestroy(HttpContext context, AnyValue config) {
}
/**
* <p>
* 预执行方法在execute方法之前运行设置当前用户信息或者加入常规统计和基础检测例如 : <br>
* <blockquote><pre>
* &#64;Override
* public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
* //设置当前用户信息
* final String sessionid = request.getSessionid(false);
* if (sessionid != null) request.setCurrentUser(userService.current(sessionid));
*
* if (finer) response.recycleListener((req, resp) -&#62; { //记录处理时间比较长的请求
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
* if (e &#62; 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
* });
* response.nextEvent();
* }
* </pre></blockquote>
* <p>
*
* @param request HttpRequest
* @param response HttpResponse
*
* @throws IOException IOException
*/
protected void preExecute(HttpRequest request, HttpResponse response) throws IOException {
response.nextEvent();
}
/**
* <p>
* 用户登录或权限验证, 注解为&#64;HttpMapping.auth == true 的方法会执行authenticate方法, 若验证成功则必须调用response.nextEvent();进行下一步操作, 例如: <br>
* <blockquote><pre>
* &#64;Override
* public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
* UserInfo info = request.currentUser();
* if (info == null) {
* response.finishJson(RET_UNLOGIN);
* return;
* } else if (!info.checkAuth(request.getModuleid(), request.getActionid())) {
* response.finishJson(RET_AUTHILLEGAL);
* return;
* }
* response.nextEvent();
* }
* </pre></blockquote>
* <p>
*
*
* @param request HttpRequest
* @param response HttpResponse
*
* @throws IOException IOException
*/
protected void authenticate(HttpRequest request, HttpResponse response) throws IOException {
response.nextEvent();
}
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
response.thenEvent(preSuccessServlet);
preExecute(request, response);
}
private HashMap<String, Entry> load() {
WebServlet module = this.getClass().getAnnotation(WebServlet.class);
final int serviceid = module == null ? 0 : module.moduleid();
final HashMap<String, Entry> map = new HashMap<>();
HashMap<String, Class> nameset = new HashMap<>();
final Class selfClz = this.getClass();
Class clz = this.getClass();
do {
if (java.lang.reflect.Modifier.isAbstract(clz.getModifiers())) break;
for (final Method method : clz.getMethods()) {
//-----------------------------------------------
String methodname = method.getName();
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
//-----------------------------------------------
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
|| paramTypes[1] != HttpResponse.class) continue;
//-----------------------------------------------
Class[] exps = method.getExceptionTypes();
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
final HttpMapping mapping = method.getAnnotation(HttpMapping.class);
if (mapping == null) continue;
final boolean inherited = mapping.inherited();
if (!inherited && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = mapping.actionid();
final String name = mapping.url().trim();
final String[] methods = mapping.methods();
if (nameset.containsKey(name)) {
if (nameset.get(name) != clz) continue;
throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + HttpMapping.class.getSimpleName() + "(" + name + ")");
}
nameset.put(name, clz);
map.put(name, new Entry(serviceid, actionid, name, methods, method, createHttpServlet(method)));
}
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
return map;
}
private HttpServlet createHttpServlet(final Method method) {
//------------------------------------------------------------------------------
final String supDynName = HttpServlet.class.getName().replace('.', '/');
final String interName = this.getClass().getName().replace('.', '/');
final String interDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(this.getClass());
final String requestSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Request.class);
final String responseSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Response.class);
final String requestDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpRequest.class);
final String responseDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpResponse.class);
String newDynName = interName + "_Dyn_" + method.getName();
int i = 0;
for (;;) {
try {
Class.forName(newDynName.replace('/', '.'));
newDynName += "_" + (++i);
} catch (Throwable ex) {
break;
}
}
//------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
final String factfield = "_factServlet";
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
{
fv = cw.visitField(ACC_PUBLIC, factfield, interDesc, null, null);
fv.visitEnd();
}
{ //构造函数
mv = (cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = (cw.visitMethod(ACC_PUBLIC, "execute", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/io/IOException"}));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, factfield, interDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, interName, method.getName(), "(" + requestDesc + responseDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "execute", "(" + requestSupDesc + responseSupDesc + ")V", null, new String[]{"java/io/IOException"});
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, HttpRequest.class.getName().replace('.', '/'));
mv.visitVarInsn(ALOAD, 2);
mv.visitTypeInsn(CHECKCAST, HttpResponse.class.getName().replace('.', '/'));
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "execute", "(" + requestDesc + responseDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
cw.visitEnd();
//------------------------------------------------------------------------------
byte[] bytes = cw.toByteArray();
Class<?> newClazz = new ClassLoader(this.getClass().getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
try {
HttpServlet instance = (HttpServlet) newClazz.newInstance();
instance.getClass().getField(factfield).set(instance, this);
return instance;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static final class Entry {
public Entry(int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) {
this.moduleid = moduleid;
this.actionid = actionid;
this.name = name;
this.methods = methods;
this.method = method;
this.servlet = servlet;
HttpMapping mapping = method.getAnnotation(HttpMapping.class);
this.ignore = mapping == null || !mapping.auth();
this.cacheseconds = mapping == null ? 0 : mapping.cacheseconds();
this.cache = cacheseconds > 0 ? new ConcurrentHashMap() : null;
this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus();
if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
cache.put(response.getRequest().getRequestURI(), ce);
return ce.getBuffers();
} : null;
}
public boolean isNeedCheck() {
return this.moduleid != 0 || this.actionid != 0;
}
public boolean checkMethod(final String reqMethod) {
if (methods.length == 0) return true;
for (String m : methods) {
if (reqMethod.equalsIgnoreCase(m)) return true;
}
return false;
}
public final HttpResponse.BufferHandler cacheHandler;
public final ConcurrentHashMap<String, CacheEntry> cache;
public final int cacheseconds;
public final boolean ignore;
public final int moduleid;
public final int actionid;
public final String name;
public final String[] methods;
public final Method method;
public final HttpServlet servlet;
}
private static final class CacheEntry {
public final long time = System.currentTimeMillis();
private final ByteBuffer[] buffers;
private final int status;
private final String contentType;
public CacheEntry(int status, String contentType, ByteBuffer[] bufs) {
this.status = status;
this.contentType = contentType;
final ByteBuffer[] newBuffers = new ByteBuffer[bufs.length];
for (int i = 0; i < newBuffers.length; i++) {
newBuffers[i] = bufs[i].duplicate().asReadOnlyBuffer();
}
this.buffers = newBuffers;
}
public ByteBuffer[] getBuffers() {
final ByteBuffer[] newBuffers = new ByteBuffer[buffers.length];
for (int i = 0; i < newBuffers.length; i++) {
newBuffers[i] = buffers[i].duplicate();
}
return newBuffers;
}
}
}

View File

@@ -5,12 +5,15 @@
*/
package org.redkale.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* RestMapping 的多用类
* 配合 HttpServlet 使用
* 用于指定HttpRequest.currentUser的数据类型<br>
* 注意 数据类型是JavaBean则必须要用javax.persistence.Id标记主键字段用于确定用户ID
*
* <p>
* 详情见: https://redkale.org
*
@@ -18,9 +21,10 @@ import static java.lang.annotation.RetentionPolicy.*;
*/
@Inherited
@Documented
@Target({METHOD})
@Target({TYPE})
@Retention(RUNTIME)
public @interface RestMappings {
public @interface HttpUserType {
Class value();
RestMapping[] value();
}

View File

@@ -8,6 +8,7 @@ package org.redkale.net.http;
import java.util.*;
/**
* MimeType
*
* <p>
* 详情见: https://redkale.org
@@ -100,6 +101,7 @@ public class MimeType {
contentTypes.put("oda", "application/oda");
contentTypes.put("ogg", "application/ogg");
contentTypes.put("out", "text/plain");
contentTypes.put("pac", "application/x-javascript-config");
contentTypes.put("pbm", "image/x-portable-bitmap");
contentTypes.put("pct", "image/pict");
contentTypes.put("pdf", "application/pdf");

View File

@@ -15,6 +15,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
/**
* HTTP的文件上传请求的上下文对象
*
* <p>
* 详情见: https://redkale.org
@@ -58,7 +59,7 @@ public final class MultiContext {
public MultiContext(final Charset charsetName, final String contentType, final DefaultAnyValue params, final InputStream in, String fielnameRegex) {
this.charset = charsetName == null ? UTF8 : charsetName;
this.contentType = contentType.trim();
this.contentType = contentType == null ? "" : contentType.trim();
this.parameters = params;
this.boundary = parseBoundary(this.contentType);
this.endboundarray = ("--" + this.boundary + "--").getBytes();
@@ -77,10 +78,122 @@ public final class MultiContext {
return null;
}
/**
* 判断请求是否包含上传文件
*
* @return boolean
*/
public boolean isMultipart() {
return this.boundary != null;
}
//或被 REST 用到
/**
* 获取第一个文件的二进制
*
* @param max 可接收的文件大小最大值
* @param filenameReg 可接收的文件名正则表达式
* @param contentTypeReg 可接收的ContentType正则表达式
*
* @return 二进制文件
* @throws IOException IOException
*/
public byte[] partsFirstBytes(final long max, final String filenameReg, final String contentTypeReg) throws IOException {
if (!isMultipart()) return null;
byte[] tmpfile = null;
boolean has = false;
for (MultiPart part : parts()) {
if (has) continue;//不遍历完后面getParameter可能获取不到值
has = true;
if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue;
if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue;
tmpfile = part.getContentBytes(max < 1 ? Long.MAX_VALUE : max);
}
return tmpfile;
}
//或被 REST 用到
/**
* 获取第一个文件
*
* @param home 进程目录
* @param max 可接收的文件大小最大值
* @param filenameReg 可接收的文件名正则表达式
* @param contentTypeReg 可接收的ContentType正则表达式
*
* @return 文件
* @throws IOException IOException
*/
public File partsFirstFile(final File home, final long max, final String filenameReg, final String contentTypeReg) throws IOException {
if (!isMultipart()) return null;
File tmpfile = null;
boolean has = false;
for (MultiPart part : parts()) {
if (has) continue; //不遍历完后面getParameter可能获取不到值
has = true;
if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue;
if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue;
String name = part.getFilename();
int pos = name.lastIndexOf('.');
if (pos > 0) {
int pos2 = name.lastIndexOf('.', pos - 1);
if (pos2 >= 0) pos = pos2;
}
File file = new File(home, "tmp/redkale_" + System.nanoTime() + (pos > 0 ? name.substring(pos) : name));
file.getParentFile().mkdirs();
boolean rs = part.save(max < 1 ? Long.MAX_VALUE : max, file);
if (!rs) {
file.delete();
} else {
tmpfile = file;
}
}
return tmpfile;
}
//或被 REST 用到
/**
* 获取所有文件
*
* @param home 进程目录
* @param max 可接收的文件大小最大值
* @param filenameReg 可接收的文件名正则表达式
* @param contentTypeReg 可接收的ContentType正则表达式
*
* @return 文件列表
* @throws IOException IOException
*/
public File[] partsFiles(final File home, final long max, final String filenameReg, final String contentTypeReg) throws IOException {
if (!isMultipart()) return null;
List<File> files = null;
for (MultiPart part : parts()) {
if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue;
if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue;
String name = part.getFilename();
int pos = name.lastIndexOf('.');
if (pos > 0) {
int pos2 = name.lastIndexOf('.', pos - 1);
if (pos2 >= 0) pos = pos2;
}
File file = new File(home, "tmp/redkale_" + System.nanoTime() + (pos > 0 ? name.substring(pos) : name));
file.getParentFile().mkdirs();
boolean rs = part.save(max < 1 ? Long.MAX_VALUE : max, file);
if (!rs) {
file.delete();
continue;
}
if (files == null) files = new ArrayList<>();
files.add(file);
}
return files == null ? null : files.toArray(new File[files.size()]);
}
/**
* 获取上传文件信息列表
*
* @return Iterable
* @throws IOException IOException
*/
public Iterable<MultiPart> parts() throws IOException {
if (!isMultipart()) return emptyIterable;
final String boundarystr = "--" + this.boundary;

File diff suppressed because it is too large Load Diff

View File

@@ -25,4 +25,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface RestAddress {
/**
* 备注描述, 对应&#64;HttpParam.comment
*
* @return String
*/
String comment() default "";
}

View File

@@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 只能注解于RestService类的方法的String/byte[]/JavaBean参数或参数内的String/byte[]/JavaBean字段
* <p>
* 用于获取HTTP请求端的请求内容UTF-8编码字符串、byte[]、JavaBean
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface RestBody {
/**
* 备注描述, 对应&#64;HttpParam.comment
*
* @return String
*/
String comment() default "";
}

View File

@@ -10,7 +10,7 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 只能注解于Service类的方法的String参数或参数内的String字段
* 只能注解于RestService类的方法的String参数或参数内的String字段
* <p>
* 详情见: https://redkale.org
*
@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface RestCookie {
String name(); //cookie名
/**
* cookie名
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
/**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
String comment() default ""; //备注描述
/**
* 备注描述
*
* @return String
*/
String comment() default "";
}

View File

@@ -10,7 +10,7 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 只能注解于Service类的方法的参数或参数内的String字段
* 只能注解于RestService类的方法的参数或参数内的String字段
* <p>
* 详情见: https://redkale.org
*
@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface RestHeader {
String name(); //参数名
/**
* Header参数名
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
/**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
String comment() default ""; //备注描述
/**
* 备注描述
*
* @return String
*/
String comment() default "";
}

View File

@@ -8,37 +8,19 @@ package org.redkale.net.http;
import java.io.*;
/**
* 使用 RestServlet 代替
*
* 详情见: https://redkale.org
*
* @author zhangjx
* @deprecated
* @param <T> 当前用户对象类型
*/
public abstract class RestHttpServlet<T> extends HttpBaseServlet {
@Deprecated
public class RestHttpServlet<T> extends HttpServlet {
protected abstract T currentUser(HttpRequest req) throws IOException;
protected void finishJson(final HttpResponse response, RestOutput output) throws IOException {
if (output == null) {
response.finishJson(output);
return;
}
response.addHeader(output.getHeaders());
response.addCookie(output.getCookies());
if (output.getResult() instanceof File) {
response.finish((File) output.getResult());
} else {
response.finishJson(output.getResult());
}
}
protected void finishJsResult(final HttpResponse response, final String var, RestOutput output) throws IOException {
if (output != null) {
response.addHeader(output.getHeaders());
response.addCookie(output.getCookies());
}
response.finishJsResult(var, output == null ? null : output.getResult());
protected T currentUser(HttpRequest req) throws IOException {
return null;
}
}

View File

@@ -10,8 +10,8 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* 只能依附在Service实现类的public方法上
* value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService的默认路径为/hello)。
* 只能依附在Service实现类的public方法上 <br>
* value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService的默认路径为/hello)。 <br>
* <p>
* 详情见: https://redkale.org
*
@@ -21,28 +21,65 @@ import static java.lang.annotation.RetentionPolicy.*;
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@Repeatable(RestMappings.class)
@Repeatable(RestMapping.RestMappings.class)
public @interface RestMapping {
boolean ignore() default false; //是否屏蔽该方法的转换
/**
* 是否屏蔽该方法进行HttpMapping转换
*
* @return boolean
*/
boolean ignore() default false;
/**
* 请求的方法名, 不能含特殊字符
* 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX、existsXXX且XXXService为Service的类名将只截取XXX之前)
*
* @return name
* @return String
*/
String name() default "";
String comment() default ""; //备注描述, 对应&#64;WebAction.comment
/**
* 备注描述, 对应&#64;HttpMapping.comment
*
* @return String
*/
String comment() default "";
boolean auth() default false; //是否鉴权,默认不鉴权, 对应&#64;AuthIgnore
/**
* 是否鉴权,默认需要鉴权, 对应&#64;HttpMapping.auth
*
* @return boolean
*/
boolean auth() default true;
int actionid() default 0; //操作ID值鉴权时用到, 对应&#64;WebAction.actionid
/**
* 操作ID值鉴权时用到, 对应&#64;HttpMapping.actionid
*
* @return int
*/
int actionid() default 0;
int cacheseconds() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpCacheable.seconds
/**
* 结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpMapping.cacheseconds
*
* @return int
*/
int cacheseconds() default 0;
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebAction.methods
/**
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;HttpMapping.methods
*
* @return String[]
*/
String[] methods() default {};
String jsvar() default ""; //以application/javascript输出对象是指明js的对象名该值存在时则忽略contentType()的值
@Inherited
@Documented
@Target({METHOD})
@Retention(RUNTIME)
@interface RestMappings {
RestMapping[] value();
}
}

View File

@@ -0,0 +1,39 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 标记在RestWebSocket的接收消息方法上
*
* <br><p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface RestOnMessage {
/**
* 请求的方法名, 不能含特殊字符,不能以数字开头(能作为变量名)
*
* @return String
*/
String name();
/**
* 备注描述
*
* @return String
*/
String comment() default "";
}

View File

@@ -10,21 +10,30 @@ import java.net.HttpCookie;
import java.util.*;
/**
* 使用 HttpResult 代替
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated
* @author zhangjx
* @param <T> 结果对象的类型
*/
@Deprecated
public class RestOutput<T> {
private Map<String, String> headers;
private List<HttpCookie> cookies;
private String contentType;
private T result;
private int status = 0; //不设置则为 200
private String message;
public RestOutput() {
}
@@ -32,14 +41,16 @@ public class RestOutput<T> {
this.result = result;
}
public void addHeader(String name, Serializable value) {
public RestOutput<T> addHeader(String name, Serializable value) {
if (this.headers == null) this.headers = new HashMap<>();
this.headers.put(name, String.valueOf(value));
return this;
}
public void addCookie(HttpCookie cookie) {
public RestOutput<T> addCookie(HttpCookie cookie) {
if (this.cookies == null) this.cookies = new ArrayList<>();
this.cookies.add(cookie);
return this;
}
public Map<String, String> getHeaders() {
@@ -58,6 +69,14 @@ public class RestOutput<T> {
this.cookies = cookies;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public T getResult() {
return result;
}
@@ -66,4 +85,20 @@ public class RestOutput<T> {
this.result = result;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -11,10 +11,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
*
* 依附在RestService类的方法的参数上
* name='&#38;' 表示当前用户
* name='#'表示截取uri最后一段
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值
* 依附在RestService类的方法的参数上 <br>
* name='&#38;' 表示当前用户 <br>
* name='#'表示截取uri最后一段 <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* <p>
* 详情见: https://redkale.org
*
@@ -26,11 +26,36 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface RestParam {
String name(); //参数名 name='&'表示当前用户; name='#'表示截取uri最后一段; name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值
//name='&'表示当前用户;
/**
* 参数名 <br>
* name='&#38;'表示当前用户; <br>
* name='#'表示截取uri最后一段; <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* 若方法名以find、delete开头且方法的参数只有一个且参数类型是基本数据类型或String则默认值为"#" <br>
*
* @return String
*/
String name();
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
/**
* 转换数字byte/short/int/long时所用的进制数 默认10进制
*
* @return int
*/
int radix() default 10;
boolean required() default true; //参数是否必传
/**
* 参数是否必传
*
* @return boolean
*/
boolean required() default true;
String comment() default ""; //备注描述
/**
* 备注描述
*
* @return String
*/
String comment() default "";
}

View File

@@ -29,6 +29,13 @@ public @interface RestService {
*/
String name() default "";
/**
* 目录名, 不能含特殊字符, 只能小写字母+数字,且不能以数字开头
*
* @return 目录名
*/
String catalog() default "";
/**
* 模块ID值鉴权时用到, 对应&#64;WebServlet.moduleid
*
@@ -36,6 +43,13 @@ public @interface RestService {
*/
int moduleid() default 0;
/**
* 没有标记&#64;RestMapping的方法是否转换 默认为false
*
* @return 默认false
*/
boolean automapping() default false;
/**
* 是否屏蔽该类的转换
*

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