156 Commits
1.3.0 ... 1.6.0

Author SHA1 Message Date
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
Redkale
9a29a11e22 2017-02-25 12:53:54 +08:00
Redkale
d73a27be71 2017-02-25 12:44:24 +08:00
Redkale
d77f424504 2017-02-25 12:27:19 +08:00
Redkale
3142ad6041 2017-02-24 15:46:00 +08:00
Redkale
6044f014c7 2017-02-24 09:04:16 +08:00
Redkale
d1cfdfa14f 2017-02-23 20:33:03 +08:00
Redkale
8f9bfc3f28 兼容javax.persistence.jdbc.driver为空的情况 2017-02-23 20:16:58 +08:00
Redkale
9ae847d392 FilterFuncColumn支持多字段名 2017-02-23 19:26:13 +08:00
Redkale
178226b730 DataSource增加getNumberMap方法,用于查询多个字段的统计值 2017-02-23 19:06:40 +08:00
Redkale
801e45abce 2017-02-23 17:45:01 +08:00
Redkale
cd54a7040a 2017-02-23 15:40:17 +08:00
Redkale
3bd880b061 2017-02-23 15:29:04 +08:00
Redkale
bf355cce28 2017-02-23 15:15:43 +08:00
Redkale
58d08c5787 @Cacheable增加定时更新缓存功能 2017-02-22 20:57:13 +08:00
Redkale
a778af73d8 修复HttpRequest.getRemoteAddress()方法中channel已关闭会抛空指针异常的BUG 2017-02-22 16:06:40 +08:00
Redkale
7ca95c3549 2017-02-22 09:10:40 +08:00
Redkale
54933ac3ac Utility增加 删除掉字符串数组中包含指定的字符串 方法 2017-02-21 20:27:19 +08:00
Redkale
255048bf5b Response增加output字段,便于RecycleListener获取输出结果 2017-02-21 16:35:08 +08:00
Redkale
206fa19f3e 2017-02-17 14:12:33 +08:00
Redkale
f0e9047f8c 2017-02-17 14:02:24 +08:00
Redkale
698966d551 删掉 DistributeGenerator 功能 2017-02-16 11:29:49 +08:00
Redkale
fc6b5cb458 2017-02-15 20:56:28 +08:00
Redkale
9eee3bfa58 增加 java.util.logging.FileHandler.unusual 特性 2017-02-15 20:46:30 +08:00
Redkale
0adc0845fd 2017-02-15 20:07:30 +08:00
Redkale
92f98eff5f 2017-02-15 09:57:10 +08:00
Redkale
d97f8acf23 2017-02-10 20:08:47 +08:00
Redkale
47e14bf2ec 2017-02-10 17:38:51 +08:00
Redkale
8eed4083bc 2017-02-10 16:55:39 +08:00
Redkale
9ef7641cd1 2017-02-09 16:44:31 +08:00
Redkale
bafb6065c8 2017-02-09 14:53:16 +08:00
Redkale
8b2460b8ab 2017-02-09 13:38:24 +08:00
Redkale
827172e743 2017-02-09 11:52:04 +08:00
Redkale
fa9bd30de5 2017-02-04 15:01:39 +08:00
Redkale
78e66ff74b 2017-02-04 14:59:10 +08:00
Redkale
7e8d1c3567 2017-02-04 09:04:35 +08:00
Redkale
c3a7603674 2017-02-03 17:25:56 +08:00
Redkale
4b8cfbba00 2017-02-03 16:52:57 +08:00
Redkale
30771e5366 2017-02-03 16:43:12 +08:00
Redkale
313c7f4ba1 2017-02-03 16:37:08 +08:00
Redkale
ece4215a8a 2017-02-03 15:03:11 +08:00
Redkale
7ea740edf1 Update RestParam.java 2017-02-02 17:23:02 +08:00
Redkale
716f4e6934 Update RestParam.java 2017-02-02 17:21:43 +08:00
Redkale
90ab302667 2017-01-18 22:55:29 +08:00
Redkale
4695949362 2017-01-18 19:04:57 +08:00
Redkale
4827893a0d 2017-01-18 10:54:02 +08:00
Redkale
9276f220b0 2017-01-17 20:12:38 +08:00
Redkale
4071a5d165 2017-01-17 13:37:34 +08:00
Redkale
da0ff24af6 2017-01-17 13:28:23 +08:00
Redkale
afef635146 2017-01-17 13:23:11 +08:00
Redkale
eda9d1c780 2017-01-16 14:11:35 +08:00
Redkale
4b5749bc60 2017-01-16 11:50:19 +08:00
Redkale
6bb23008c2 2017-01-11 10:37:53 +08:00
Redkale
7746971b60 2017-01-11 10:35:56 +08:00
Redkale
bc20c82fef 2017-01-11 10:24:49 +08:00
Redkale
fff70ed241 2017-01-11 10:03:43 +08:00
Redkale
c590d45ce0 2017-01-10 20:01:09 +08:00
Redkale
8bab9ad22b 2017-01-10 18:10:02 +08:00
Redkale
3c457dad2a 2017-01-10 16:42:41 +08:00
Redkale
eaae598234 2017-01-09 15:05:14 +08:00
Redkale
606faf1bf8 2017-01-09 10:38:34 +08:00
Redkale
ae9aa94323 2017-01-09 10:27:13 +08:00
Redkale
2e41e44294 2016-12-29 11:15:21 +08:00
Redkale
d806d9d6ff 2016-12-29 10:34:43 +08:00
Redkale
1260736c14 2016-12-26 17:31:34 +08:00
Redkale
08c5cbbbf3 2016-12-26 15:16:20 +08:00
Redkale
af0726cd79 2016-12-25 15:47:46 +08:00
Redkale
ce2279030d 2016-12-25 15:45:41 +08:00
Redkale
83aba2ebee 2016-12-23 18:20:04 +08:00
Redkale
5c11742b51 2016-12-17 17:14:22 +08:00
Redkale
5295e04275 2016-12-15 14:38:33 +08:00
Redkale
47f723e63b 2016-12-15 09:54:23 +08:00
Redkale
54956e47d2 2016-12-15 09:11:28 +08:00
Redkale
b2cbdf6642 2016-12-14 20:43:41 +08:00
Redkale
989d1c6db9 解决updateColumn多表关联更新的BUG 2016-12-11 20:40:29 +08:00
Redkale
e139b0cc5d 2016-12-11 19:56:33 +08:00
Redkale
66261e98b5 2016-12-11 19:22:12 +08:00
Redkale
d9a268d30a 2016-12-11 19:10:51 +08:00
Redkale
a8bc50a947 2016-12-09 17:06:26 +08:00
Redkale
6aa96daae2 2016-12-09 14:17:16 +08:00
Redkale
293805a55e 2016-12-09 11:17:03 +08:00
Redkale
8b6319888c Update README.md 2016-12-02 11:10:54 +08:00
Redkale
408676e97a Update README.md 2016-12-02 11:09:15 +08:00
Redkale
1fabbae4f6 2016-11-28 10:43:38 +08:00
Redkale
09a5b41d96 2016-11-25 17:20:45 +08:00
Redkale
9d85a4dcaf 2016-11-25 17:06:03 +08:00
Redkale
9bc60c1c47 2016-11-25 15:53:37 +08:00
Redkale
92aff864ef 2016-11-25 11:40:49 +08:00
Redkale
254e2e8ccd 2016-11-25 11:28:11 +08:00
Redkale
2480d127ac 2016-11-25 10:16:58 +08:00
Redkale
cc3d82e864 2016-11-25 10:09:06 +08:00
141 changed files with 7716 additions and 1532 deletions

View File

@@ -8,14 +8,14 @@
<li>提供HTTP服务同时内置JSON功能与限时缓存功能</li> <li>提供HTTP服务同时内置JSON功能与限时缓存功能</li>
<li>TCP层完全使用NIO.2并统一TCP与UDP的接口换</li> <li>TCP层完全使用NIO.2并统一TCP与UDP的接口换</li>
<li>提供分布式与集中式部署的无缝切换</li> <li>提供分布式与集中式部署的无缝切换</li>
<li>提供类似JPA功能包含数据缓存自动同步与简洁的数据层操作接口</li> <li>提供类似JPA功能包含数据缓存自动同步、分表分库与简洁的数据层操作接口</li>
<li>可以动态修改已依赖注入的资源</li> <li>可以动态修改已依赖注入的资源</li>
</ol> </ol>
<strong>Redkale 设计理念</strong> <strong>Redkale 设计理念</strong>
<p> <p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架,不仅是使用了Java8的新语法,更多是设计上与主流框架有不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量而且也可以动态更改已注入的资源。Spring提倡控制反转思想偏偏自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者不想使用Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务开发者想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现。这其实包含了控制反转的思想让框架里的零件可以让开发者控制。<br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架,Redkale在接口定义上使用了Java 8大量的新语法,接口有默认实现、接口带静态方法、重复注解等特性,同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量并且可动态更改已注入的资源。Spring提倡控制反转思想自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务若想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想,让框架里的各个组件均可让开发者控制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单也是Redkale的一个特点并非不足,从一个良好的设计习惯或架构上来看,有些常用功能是不需要提供的,如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集的数字计算不是Java的专长同时一个稍好的提供HTTP服务的架构不会将Java动态服务器放在最前端通常前面会放nginx或apache除了负载均衡还能静动分离既然Java服务器前面有C写的服务器那么HTTPS的加解密就应该交给前面的服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP(如果初级程序员还花大量时间去学习基于JSP的Struts或Spring MVC框架就有点跟不上时代了)。Redkale在功能上做了筛选不会只因为迎合主流而提供,而是以良好的设计思想为指导。这是Redkale很重要的一个思想 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单体现了Redkale的简易性,而并非不足从一个良好的设计习惯或架构上来看有些常用功能是不需要提供的如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集的计算不是Java的专长通常提供HTTP服务的架构不会将Java动态服务器放在最前端而是在前方会放nginx或apache除了负载均衡还能静动分离因此HTTPS的加解密应交给nginx这样的高性能服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能方便兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选不会为迎合主流而提供而是以良好的设计思想为指导。这是Redkale的主导思维
</p> </p>

140
pom.xml Normal file
View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.redkale</groupId>
<artifactId>redkale</artifactId>
<packaging>jar</packaging>
<url>http://redkale.org</url>
<description>redkale -- java framework</description>
<version>1.4.0-SNAPSHOT</version>
<licenses>
<license>
<name>Apache 2</name>
<url>http://www.apache.org/licenses/</url>
<distribution>repo</distribution>
<comments>Apache License</comments>
</license>
</licenses>
<developers>
<developer>
<id>Redkale</id>
<name>redkale</name>
<email>redkale@qq.com</email>
<url>http://redkale.org</url>
<roles>
<role>Project Manager</role>
<role>Architect</role>
</roles>
<organization>redkale</organization>
<organizationUrl>http://redkale.org</organizationUrl>
<properties>
<dept>No</dept>
</properties>
<timezone>8</timezone>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<name>Redkale</name>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<scm>
<url>https://github.com/redkale/redkale</url>
<connection>scm:git:git@github.com/redkale/redkale.git</connection>
<developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<mainClass>org.redkale.boot.Application</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</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

@@ -42,8 +42,8 @@
一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内 一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
一个group节点对应一个 Transport 对象。 一个group节点对应一个 Transport 对象。
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。 name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol只能是UDP TCP 默认TCP protocol范围:UDP TCP 默认TCP
kind: 与SNCP服务连接时的数据传输类型可选值有:rest(不区分大小写);值为空或空字符串表示按SNCP协议传输; 为rest表示按REST传输。默认值为空 subprotocol: 子协议,预留字段。默认值为空
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。 注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
--> -->
<group name="" protocol="TCP"> <group name="" protocol="TCP">
@@ -137,7 +137,7 @@
includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
--> -->
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="false" autoload="true" includes="" excludes=""> <rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes="">
<!-- <!--
value: Service类名列出的表示必须被加载的Service对象 value: Service类名列出的表示必须被加载的Service对象
ignore: 是否忽略设置为true则不会加载该Service对象默认值为false ignore: 是否忽略设置为true则不会加载该Service对象默认值为false

View File

@@ -16,6 +16,8 @@ java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 100 java.util.logging.FileHandler.count = 100
java.util.logging.FileHandler.encoding = UTF-8 java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%u.log java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%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.append = true java.util.logging.FileHandler.append = true
#java.util.logging.ConsoleHandler.level = FINE #java.util.logging.ConsoleHandler.level = FINE

View File

@@ -16,6 +16,7 @@
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource 因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
并且如果JDBC驱动是以上几个版本javax.persistence.jdbc.driver属性都可以省略Redkale会根据javax.persistence.jdbc.url的值来识别驱动
--> -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.user" value="root"/>

View File

@@ -1,4 +1,4 @@
/******************************************************************************* /** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved. * Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
* *
* This program and the accompanying materials are made available under the * This program and the accompanying materials are made available under the
@@ -12,7 +12,7 @@
* Linda DeMichiel - Java Persistence 2.1 * Linda DeMichiel - Java Persistence 2.1
* Linda DeMichiel - Java Persistence 2.0 * Linda DeMichiel - Java Persistence 2.0
* *
******************************************************************************/ ***************************************************************************** */
package javax.persistence; package javax.persistence;
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.TYPE;
@@ -28,18 +28,27 @@ import java.lang.annotation.Target;
* subclasses; it can be overridden by specifying * subclasses; it can be overridden by specifying
* <code>Cacheable</code> on a subclass. * <code>Cacheable</code> on a subclass.
* *
* <p> <code>Cacheable(false)</code> means that the entity and its state must * <p>
* <code>Cacheable(false)</code> means that the entity and its state must
* not be cached by the provider. * not be cached by the provider.
* *
* @since Java Persistence 2.0 * @since Java Persistence 2.0
*/ */
@Target( { TYPE }) @Target({TYPE})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Cacheable { public @interface Cacheable {
/** /**
* (Optional) Whether or not the entity should be cached. * (Optional) Whether or not the entity should be cached.
*
* @return boolean * @return boolean
*/ */
boolean value() default true; boolean value() default true;
/**
* (Optional) 定时自动更新缓存的周期秒数为0表示不做定时更新 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
*
* @return int
*/
int interval() default 0;
} }

View File

@@ -0,0 +1,69 @@
/** *****************************************************************************
* Copyright (c) 2011 - 2013 Oracle Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Linda DeMichiel - Java Persistence 2.1
*
***************************************************************************** */
package javax.persistence;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Used in schema generation to specify creation of an index.
* <p>
* Note that it is not necessary to specify an index for a primary key,
* as the primary key index will be created automatically.
*
* <p>
* The syntax of the <code>columnList</code> element is a
* <code>column_list</code>, as follows:
*
* <pre>
* column::= index_column [,index_column]*
* index_column::= column_name [ASC | DESC]
* </pre>
*
* <p>
* If <code>ASC</code> or <code>DESC</code> is not specified,
* <code>ASC</code> (ascending order) is assumed.
*
* @since Java Persistence 2.1
*
*/
@Target({})
@Retention(RUNTIME)
public @interface Index {
/**
* (Optional) The name of the index; defaults to a provider-generated name.
*
* @return String
*/
String name() default "";
/**
* (Required) The names of the columns to be included in the index,
* in order.
*
* @return String
*/
String columnList();
/**
* (Optional) Whether the index is unique.
*
* @return boolean
*/
boolean unique() default false;
}

View File

@@ -59,4 +59,29 @@ public @interface Table {
*/ */
String catalog() default ""; String catalog() default "";
/**
* (Optional) Unique constraints that are to be placed on
* the table. These are only used if table generation is in
* effect. These constraints apply in addition to any constraints
* specified by the <code>Column</code> and <code>JoinColumn</code>
* annotations and constraints entailed by primary key mappings.
* <p>
* Defaults to no additional constraints.
* @return UniqueConstraint[]
*/
UniqueConstraint[] uniqueConstraints() default {};
/**
* (Optional) Indexes for the table. These are only used if
* table generation is in effect. Note that it is not necessary
* to specify an index for a primary key, as the primary key
* index will be created automatically.
*
* @return indexes
* @since Java Persistence 2.1
*/
Index[] indexes() default {};
String comment() default "";
} }

View File

@@ -0,0 +1,56 @@
/** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Linda DeMichiel - Java Persistence 2.1
* Linda DeMichiel - Java Persistence 2.0
*
***************************************************************************** */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Specifies that a unique constraint is to be included in
* the generated DDL for a primary or secondary table.
*
* <pre>
* Example:
* &#064;Entity
* &#064;Table(
* name="EMPLOYEE",
* uniqueConstraints=
* &#064;UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})
* )
* public class Employee { ... }
* </pre>
*
* @since Java Persistence 1.0
*/
@Target({})
@Retention(RUNTIME)
public @interface UniqueConstraint {
/** (Optional) Constraint name. A provider-chosen name will be chosen
* if a name is not specified.
*
* @return String
* @since Java Persistence 2.0
*/
String name() default "";
/** (Required) An array of the column names that make up the constraint.
*
* @return String[]
*/
String[] columnNames();
}

View File

@@ -8,21 +8,24 @@ package org.redkale.boot;
import java.io.*; import java.io.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import javax.persistence.Column; import javax.persistence.*;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.source.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 继承 HttpBaseServlet 是为了获取 WebAction 信息 * API接口文档生成类作用生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
继承 HttpBaseServlet 是为了获取 WebMapping 信息
* *
* <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public class ApiDocs extends HttpBaseServlet { public class ApiDocs extends HttpBaseServlet {
private final Application app; private final Application app; //Application全局对象
public ApiDocs(Application app) { public ApiDocs(Application app) {
this.app = app; this.app = app;
@@ -31,7 +34,7 @@ public class ApiDocs extends HttpBaseServlet {
public void run() throws Exception { public void run() throws Exception {
List<Map> serverList = new ArrayList<>(); List<Map> serverList = new ArrayList<>();
Map<String, Map<String, Map<String, String>>> typesmap = new LinkedHashMap<>(); Map<String, Map<String, Map<String, Object>>> typesmap = new LinkedHashMap<>();
for (NodeServer node : app.servers) { for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue; if (!(node instanceof NodeHttpServer)) continue;
final Map<String, Object> map = new LinkedHashMap<>(); final Map<String, Object> map = new LinkedHashMap<>();
@@ -60,19 +63,65 @@ public class ApiDocs extends HttpBaseServlet {
servletmap.put("name", ws.name()); servletmap.put("name", ws.name());
servletmap.put("comment", ws.comment()); servletmap.put("comment", ws.comment());
List<Map> actionsList = new ArrayList<>(); List<Map> mappingsList = new ArrayList<>();
servletmap.put("actions", actionsList); servletmap.put("mappings", mappingsList);
for (Method method : servlet.getClass().getMethods()) { final Class selfClz = servlet.getClass();
Class clz = servlet.getClass();
HashSet<String> actionurls = new HashSet<>();
do {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue; if (method.getParameterCount() != 2) continue;
WebAction action = method.getAnnotation(WebAction.class); WebMapping action = method.getAnnotation(WebMapping.class);
if (action == null) continue; if (action == null) continue;
final Map<String, Object> actionmap = new LinkedHashMap<>(); if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
actionmap.put("url", prefix + action.url()); final Map<String, Object> mappingmap = new LinkedHashMap<>();
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null); if (actionurls.contains(action.url())) continue;
actionmap.put("actionid", action.actionid()); mappingmap.put("url", prefix + action.url());
actionmap.put("comment", action.comment()); actionurls.add(action.url());
mappingmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
mappingmap.put("actionid", action.actionid());
mappingmap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>(); List<Map> paramsList = new ArrayList<>();
actionmap.put("params", paramsList); mappingmap.put("params", paramsList);
List<String> results = new ArrayList<>();
for (final Class rtype : action.results()) {
results.add(rtype.getName());
if (typesmap.containsKey(rtype.getName())) continue;
final boolean filter = FilterBean.class.isAssignableFrom(rtype);
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = rtype;
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Comment comment = field.getAnnotation(Comment.class);
Column col = field.getAnnotation(Column.class);
FilterColumn fc = field.getAnnotation(FilterColumn.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
typemap.put(field.getName(), fieldmap);
}
} while ((loop = loop.getSuperclass()) != Object.class);
typesmap.put(rtype.getName(), typemap);
}
mappingmap.put("results", results);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) { for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>(); final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray(); final boolean isarray = param.type().isArray();
@@ -82,28 +131,35 @@ public class ApiDocs extends HttpBaseServlet {
parammap.put("type", ptype.getName() + (isarray ? "[]" : "")); parammap.put("type", ptype.getName() + (isarray ? "[]" : ""));
parammap.put("src", param.src()); parammap.put("src", param.src());
parammap.put("comment", param.comment()); parammap.put("comment", param.comment());
parammap.put("required", param.required());
paramsList.add(parammap); paramsList.add(parammap);
if (ptype.isPrimitive() || ptype == String.class) continue; if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesmap.containsKey(ptype.getName())) continue; if (typesmap.containsKey(ptype.getName())) continue;
final Map<String, Map<String, String>> typemap = new LinkedHashMap<>(); final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = ptype; Class loop = ptype;
final boolean filter = FilterBean.class.isAssignableFrom(loop);
do { do {
if (loop == null || loop.isInterface()) break; if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) { for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue; if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue; if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, String> fieldmap = new LinkedHashMap<>(); Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName()); fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Column col = field.getAnnotation(Column.class);
FilterColumn fc = field.getAnnotation(FilterColumn.class);
Comment comment = field.getAnnotation(Comment.class); Comment comment = field.getAnnotation(Comment.class);
if (comment != null) { if (comment != null) {
fieldmap.put("comment", comment.value()); fieldmap.put("comment", comment.value());
} else { } else if (col != null) {
Column col = field.getAnnotation(Column.class); fieldmap.put("comment", col.comment());
if (col != null) fieldmap.put("comment", col.comment()); } else if (fc != null) {
fieldmap.put("comment", fc.comment());
} }
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) { if (servlet.getClass().getAnnotation(Rest.RestDynamic.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue; if (field.getAnnotation(RestAddress.class) != null) continue;
@@ -115,10 +171,11 @@ public class ApiDocs extends HttpBaseServlet {
typesmap.put(ptype.getName(), typemap); typesmap.put(ptype.getName(), typemap);
} }
actionmap.put("result", action.result()); mappingmap.put("result", action.result());
actionsList.add(actionmap); mappingsList.add(mappingmap);
} }
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url"))); } while ((clz = clz.getSuperclass()) != HttpServlet.class);
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletmap); servletsList.add(servletmap);
} }
servletsList.sort((o1, o2) -> { servletsList.sort((o1, o2) -> {
@@ -140,7 +197,7 @@ public class ApiDocs extends HttpBaseServlet {
in = new FileInputStream(doctemplate); in = new FileInputStream(doctemplate);
} }
if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html"); if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html");
String content = Utility.read(in).replace("${content}", json); String content = Utility.read(in).replace("'${content}'", json);
in.close(); in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html")); FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes("UTF-8")); outhtml.write(content.getBytes("UTF-8"));

View File

@@ -30,9 +30,17 @@ import org.redkale.watch.WatchFactory;
import org.w3c.dom.*; import org.w3c.dom.*;
/** /**
* 编译时需要加入: -XDignore.symbol.file=true *
* 进程启动类,全局对象。 <br>
* <pre>
* 程序启动执行步骤:
* 1、读取application.xml
* 2、进行classpath扫描动态加载Service与Servlet
* 3、优先加载所有SNCP协议的服务再加载其他协议服务
* 4、最后进行Service、Servlet与其他资源之间的依赖注入
* </pre>
* <p> * <p>
* 进程启动类程序启动后读取application.xml,进行classpath扫描动态加载Service与Servlet 优先加载所有SNCP协议的服务 再加载其他协议服务, 最后进行Service、Servlet与其他资源之间的依赖注入。 * 编译时需要加入: -XDignore.symbol.file=true
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -40,65 +48,99 @@ import org.w3c.dom.*;
*/ */
public final class Application { public final class Application {
//当前进程启动的时间, 类型: long /**
* 当前进程启动的时间, 类型: long
*/
public static final String RESNAME_APP_TIME = "APP_TIME"; public static final String RESNAME_APP_TIME = "APP_TIME";
//当前进程的根目录, 类型String、File、Path /**
* 当前进程的根目录, 类型String、File、Path
*/
public static final String RESNAME_APP_HOME = "APP_HOME"; public static final String RESNAME_APP_HOME = "APP_HOME";
//application.xml 文件中resources节点的内容 类型: AnyValue /**
* application.xml 文件中resources节点的内容 类型: AnyValue
*/
public static final String RESNAME_APP_GRES = "APP_GRES"; public static final String RESNAME_APP_GRES = "APP_GRES";
//当前进程节点的name 类型String /**
* 当前进程节点的name 类型String
*/
public static final String RESNAME_APP_NODE = "APP_NODE"; public static final String RESNAME_APP_NODE = "APP_NODE";
//当前进程节点的IP地址 类型InetAddress、String /**
* 当前进程节点的IP地址 类型InetAddress、String
*/
public static final String RESNAME_APP_ADDR = "APP_ADDR"; public static final String RESNAME_APP_ADDR = "APP_ADDR";
//当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String /**
* 当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
*/
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR"; public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR";
//当前SNCP Server所属的组 类型: String /**
* 当前SNCP Server所属的组 类型: String
*/
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP"; public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP";
//当前Server的ROOT目录 类型String、File、Path /**
* 当前Server的ROOT目录 类型String、File、Path
*/
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT; public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
//每个地址对应的Group名
final Map<InetSocketAddress, String> globalNodes = new HashMap<>(); final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
//协议地址的Group集合
final Map<String, GroupInfo> globalGroups = new HashMap<>(); final Map<String, GroupInfo> globalGroups = new HashMap<>();
//本地IP地址
final InetAddress localAddress; final InetAddress localAddress;
//CacheSource 资源
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>(); final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
//DataSource 资源
final List<DataSource> dataSources = new CopyOnWriteArrayList<>(); final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
//NodeServer 资源
final List<NodeServer> servers = new CopyOnWriteArrayList<>(); final List<NodeServer> servers = new CopyOnWriteArrayList<>();
//传输端的ByteBuffer对象池
final ObjectPool<ByteBuffer> transportBufferPool; final ObjectPool<ByteBuffer> transportBufferPool;
//传输端的线程池
final ExecutorService transportExecutor; final ExecutorService transportExecutor;
//传输端的ChannelGroup
final AsynchronousChannelGroup transportChannelGroup; final AsynchronousChannelGroup transportChannelGroup;
//全局根ResourceFactory
final ResourceFactory resourceFactory = ResourceFactory.root(); final ResourceFactory resourceFactory = ResourceFactory.root();
//临时计数器
CountDownLatch servicecdl; //会出现两次赋值 CountDownLatch servicecdl; //会出现两次赋值
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
//是否用于main方法运行
private final boolean singletonrun; private final boolean singletonrun;
//根WatchFactory
private final WatchFactory watchFactory = WatchFactory.root(); private final WatchFactory watchFactory = WatchFactory.root();
//进程根目录
private final File home; private final File home;
//日志
private final Logger logger; private final Logger logger;
//服务配置项
private final AnyValue config; private final AnyValue config;
//服务启动时间
private final long startTime = System.currentTimeMillis(); private final long startTime = System.currentTimeMillis();
//Server启动的计数器用于确保所有Server都启动完后再进行下一步处理
private final CountDownLatch serversLatch; private final CountDownLatch serversLatch;
private Application(final AnyValue config) { private Application(final AnyValue config) {
@@ -164,7 +206,8 @@ public final class Application {
Properties prop = new Properties(); Properties prop = new Properties();
final String handlers = properties.getProperty("handlers"); final String handlers = properties.getProperty("handlers");
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) { if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", fileHandlerClass)); //singletonrun模式下不输出文件日志
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", singletonrun ? "" : fileHandlerClass));
} }
if (!prop.isEmpty()) { if (!prop.isEmpty()) {
String prefix = fileHandlerClass + "."; String prefix = fileHandlerClass + ".";
@@ -189,6 +232,7 @@ public final class Application {
} }
this.logger = Logger.getLogger(this.getClass().getSimpleName()); this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1); this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
logger.log(Level.INFO, "------------------------------- Redkale -------------------------------");
//------------------配置 <transport> 节点 ------------------ //------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null; ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null; ExecutorService transportExec = null;
@@ -332,7 +376,7 @@ public final class Application {
} }
GroupInfo ginfo = globalGroups.get(group); GroupInfo ginfo = globalGroups.get(group);
if (ginfo == null) { if (ginfo == null) {
ginfo = new GroupInfo(group, protocol, conf.getValue("kind", ""), new LinkedHashSet<>()); ginfo = new GroupInfo(group, protocol, conf.getValue("subprotocol", ""), new LinkedHashSet<>());
globalGroups.put(group, ginfo); globalGroups.put(group, ginfo);
} }
for (AnyValue node : conf.getAnyValues("node")) { for (AnyValue node : conf.getAnyValues("node")) {
@@ -422,6 +466,7 @@ public final class Application {
channel.write(buffer); channel.write(buffer);
buffer.clear(); buffer.clear();
channel.configureBlocking(false); channel.configureBlocking(false);
try {
channel.read(buffer); channel.read(buffer);
buffer.flip(); buffer.flip();
byte[] bytes = new byte[buffer.remaining()]; byte[] bytes = new byte[buffer.remaining()];
@@ -429,6 +474,19 @@ public final class Application {
channel.close(); channel.close();
logger.info(new String(bytes)); logger.info(new String(bytes));
Thread.sleep(500); 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 ApiDocs(application).run();
logger.info("APIDOC OK");
return;
}
}
throw e;
}
} }
public void start() throws Exception { public void start() throws Exception {
@@ -462,7 +520,7 @@ public final class Application {
for (final AnyValue serconf : serconfs) { for (final AnyValue serconf : serconfs) {
Thread thread = new Thread() { Thread thread = new Thread() {
{ {
String host = serconf.getValue("host", "").replace("0.0.0.0", "[0]"); String host = serconf.getValue("host", "0.0.0.0").replace("0.0.0.0", "*");
setName(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread"); setName(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
this.setDaemon(true); this.setDaemon(true);
} }

View File

@@ -28,9 +28,9 @@ import org.redkale.util.AnyValue.DefaultAnyValue;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class ClassFilter<T> { public final class ClassFilter<T> {
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
private static final boolean finer = logger.isLoggable(Level.FINER); private static final boolean finer = logger.isLoggable(Level.FINER); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果 private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果

View File

@@ -7,8 +7,10 @@ package org.redkale.boot;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.*; import java.util.*;
import org.redkale.convert.json.JsonConvert;
/** /**
* 协议地址组合对象, 对应application.xml 中 resources-&#62;group 节点信息
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -17,21 +19,21 @@ import java.util.*;
*/ */
public class GroupInfo { public class GroupInfo {
protected String name; protected String name; //地址
protected String protocol; protected String protocol; //协议 取值范围: TCP、UDP
protected String kind; protected String subprotocol; //子协议,预留使用
protected Set<InetSocketAddress> addrs; protected Set<InetSocketAddress> addrs; //地址列表, 对应 resources-&#62;group-&#62;node节点信息
public GroupInfo() { public GroupInfo() {
} }
public GroupInfo(String name, String protocol, String kind, Set<InetSocketAddress> addrs) { public GroupInfo(String name, String protocol, String subprotocol, Set<InetSocketAddress> addrs) {
this.name = name; this.name = name;
this.protocol = protocol; this.protocol = protocol;
this.kind = kind; this.subprotocol = subprotocol;
this.addrs = addrs; this.addrs = addrs;
} }
@@ -51,12 +53,12 @@ public class GroupInfo {
this.protocol = protocol; this.protocol = protocol;
} }
public String getKind() { public String getSubprotocol() {
return kind; return subprotocol;
} }
public void setKind(String kind) { public void setSubprotocol(String subprotocol) {
this.kind = kind; this.subprotocol = subprotocol;
} }
public Set<InetSocketAddress> getAddrs() { public Set<InetSocketAddress> getAddrs() {
@@ -71,4 +73,8 @@ public class GroupInfo {
this.addrs = addrs; this.addrs = addrs;
} }
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
} }

View File

@@ -84,9 +84,13 @@ public class LogFileHandler extends Handler {
private String pattern; private String pattern;
private String unusual; //不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中
private int limit; //文件大小限制 private int limit; //文件大小限制
private final AtomicInteger index = new AtomicInteger(); private final AtomicInteger logindex = new AtomicInteger();
private final AtomicInteger logunusualindex = new AtomicInteger();
private int count = 1; //文件限制 private int count = 1; //文件限制
@@ -94,11 +98,17 @@ public class LogFileHandler extends Handler {
private boolean append; private boolean append;
private final AtomicLong length = new AtomicLong(); private final AtomicLong loglength = new AtomicLong();
private final AtomicLong logunusuallength = new AtomicLong();
private File logfile; private File logfile;
private OutputStream stream; private File logunusualfile;
private OutputStream logstream;
private OutputStream logunusualstream;
public LogFileHandler() { public LogFileHandler() {
updateTomorrow(); updateTomorrow();
@@ -114,7 +124,7 @@ public class LogFileHandler extends Handler {
cal.set(Calendar.MILLISECOND, 0); cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.DAY_OF_YEAR, 1); cal.add(Calendar.DAY_OF_YEAR, 1);
long t = cal.getTimeInMillis(); long t = cal.getTimeInMillis();
if (this.tomorrow != t) index.set(0); if (this.tomorrow != t) logindex.set(0);
this.tomorrow = t; this.tomorrow = t;
} }
@@ -131,35 +141,59 @@ public class LogFileHandler extends Handler {
while (true) { while (true) {
try { try {
LogRecord record = records.take(); LogRecord record = records.take();
final boolean bigger = (limit > 0 && limit <= length.get()); final boolean bigger = (limit > 0 && limit <= loglength.get());
if (bigger || tomorrow <= record.getMillis()) { final boolean changeday = tomorrow <= record.getMillis();
if (bigger || changeday) {
updateTomorrow(); updateTomorrow();
if (stream != null) { if (logstream != null) {
stream.close(); logstream.close();
if (bigger) { if (bigger) {
for (int i = Math.min(count - 2, index.get() - 1); i > 0; i--) { for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) {
File greater = new File(logfile.getPath() + "." + i); File greater = new File(logfile.getPath() + "." + i);
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} }
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} }
stream = null; logstream = null;
} }
} }
if (stream == null) { if (unusual != null && changeday && logunusualstream != null) {
index.incrementAndGet(); logunusualstream.close();
if (limit > 0 && limit <= logunusuallength.get()) {
for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) {
File greater = new File(logunusualfile.getPath() + "." + i);
if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
logunusualstream = null;
}
if (logstream == null) {
logindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now(); java.time.LocalDate date = LocalDate.now();
logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth())))); logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logfile.getParentFile().mkdirs(); logfile.getParentFile().mkdirs();
length.set(logfile.length()); loglength.set(logfile.length());
stream = new FileOutputStream(logfile, append); logstream = new FileOutputStream(logfile, append);
}
if (unusual != null && logunusualstream == null) {
logunusualindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now();
logunusualfile = new File(unusual.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logunusualfile.getParentFile().mkdirs();
logunusuallength.set(logunusualfile.length());
logunusualstream = new FileOutputStream(logunusualfile, append);
} }
//----------------------写日志------------------------- //----------------------写日志-------------------------
String message = getFormatter().format(record); String message = getFormatter().format(record);
String encoding = getEncoding(); String encoding = getEncoding();
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding); byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
stream.write(bytes); logstream.write(bytes);
length.addAndGet(bytes.length); loglength.addAndGet(bytes.length);
if (unusual != null && (record.getLevel() == Level.WARNING || record.getLevel() == Level.SEVERE)) {
logunusualstream.write(bytes);
logunusuallength.addAndGet(bytes.length);
}
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE); if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE);
@@ -177,30 +211,39 @@ public class LogFileHandler extends Handler {
private void configure() { private void configure() {
LogManager manager = LogManager.getLogManager(); LogManager manager = LogManager.getLogManager();
String cname = LogFileHandler.class.getName(); String cname = LogFileHandler.class.getName();
pattern = manager.getProperty(cname + ".pattern"); this.pattern = manager.getProperty(cname + ".pattern");
if (pattern == null) { if (this.pattern == null) {
pattern = "logs-%m/" + getPrefix() + "log-%d.log"; this.pattern = "logs-%m/" + getPrefix() + "log-%d.log";
} else { } else {
int pos = pattern.lastIndexOf('/'); int pos = this.pattern.lastIndexOf('/');
if (pos > 0) { if (pos > 0) {
pattern = pattern.substring(0, pos + 1) + getPrefix() + pattern.substring(pos + 1); this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1);
} else { } else {
pattern = getPrefix() + pattern; this.pattern = getPrefix() + this.pattern;
}
}
String unusualstr = manager.getProperty(cname + ".unusual");
if (unusualstr != null) {
int pos = unusualstr.lastIndexOf('/');
if (pos > 0) {
this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1);
} else {
this.unusual = getPrefix() + unusualstr;
} }
} }
String limitstr = manager.getProperty(cname + ".limit"); String limitstr = manager.getProperty(cname + ".limit");
try { try {
if (limitstr != null) limit = Math.abs(Integer.decode(limitstr)); if (limitstr != null) this.limit = Math.abs(Integer.decode(limitstr));
} catch (Exception e) { } catch (Exception e) {
} }
String countstr = manager.getProperty(cname + ".count"); String countstr = manager.getProperty(cname + ".count");
try { try {
if (countstr != null) count = Math.max(1, Math.abs(Integer.decode(countstr))); if (countstr != null) this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
} catch (Exception e) { } catch (Exception e) {
} }
String appendstr = manager.getProperty(cname + ".append"); String appendstr = manager.getProperty(cname + ".append");
try { try {
if (appendstr != null) append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr); if (appendstr != null) this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
} catch (Exception e) { } catch (Exception e) {
} }
String levelstr = manager.getProperty(cname + ".level"); String levelstr = manager.getProperty(cname + ".level");
@@ -256,7 +299,7 @@ public class LogFileHandler extends Handler {
@Override @Override
public void flush() { public void flush() {
try { try {
if (stream != null) stream.flush(); if (logstream != null) logstream.flush();
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE); if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE);
@@ -266,7 +309,7 @@ public class LogFileHandler extends Handler {
@Override @Override
public void close() throws SecurityException { public void close() throws SecurityException {
try { try {
if (stream != null) stream.close(); if (logstream != null) logstream.close();
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE); if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE);

View File

@@ -29,7 +29,7 @@ import org.redkale.util.*;
@NodeProtocol({"HTTP"}) @NodeProtocol({"HTTP"})
public class NodeHttpServer extends NodeServer { public class NodeHttpServer extends NodeServer {
protected final boolean rest; protected final boolean rest; //是否加载REST服务 为true加载rest节点信息并将所有可REST化的Service生成RestHttpServlet
protected final HttpServer httpServer; protected final HttpServer httpServer;
@@ -131,7 +131,7 @@ public class NodeHttpServer extends NodeServer {
if (as.getKey().length() > max) max = as.getKey().length(); if (as.getKey().length() > max) max = as.getKey().length();
} }
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Loaded ").append(as.getKey()); sb.append(threadName).append(" Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) { for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' '); sb.append(' ');
} }
@@ -202,7 +202,7 @@ public class NodeHttpServer extends NodeServer {
if (as.getKey().length() > max) max = as.getKey().length(); if (as.getKey().length() > max) max = as.getKey().length();
} }
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Loaded ").append(as.getKey()); sb.append(threadName).append(" Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) { for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' '); sb.append(' ');
} }

View File

@@ -9,6 +9,7 @@ import java.util.Objects;
import org.redkale.service.Service; import org.redkale.service.Service;
/** /**
* NodeServer的拦截类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -17,10 +18,22 @@ import org.redkale.service.Service;
*/ */
public class NodeInterceptor { public class NodeInterceptor {
/** *
* Server.start之前调用 <br>
* NodeServer.start的部署是先执行NodeInterceptor.preStart再执行 Server.start 方法
*
* @param server NodeServer
*/
public void preStart(NodeServer server) { public void preStart(NodeServer server) {
} }
/**
* Server.shutdown之前调用 <br>
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown再执行 Server.sshutdown 方法
*
* @param server NodeServer
*/
public void preShutdown(NodeServer server) { public void preShutdown(NodeServer server) {
} }

View File

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

View File

@@ -276,8 +276,8 @@ public abstract class NodeServer {
if (WebSocketNode.class.isAssignableFrom(type)) continue; if (WebSocketNode.class.isAssignableFrom(type)) continue;
} }
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty()); if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
if (resourceFactory.find(entry.getName(), type) != null) { //Server加载Service时需要判断是否已经加载过了。
Service oldother = resourceFactory.find(entry.getName(), type); Service oldother = resourceFactory.find(entry.getName(), type);
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother)); interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother));
continue; continue;
} }
@@ -347,7 +347,7 @@ public abstract class NodeServer {
}); });
if (sb != null) { if (sb != null) {
remoteServiceWrappers.forEach(y -> { remoteServiceWrappers.forEach(y -> {
sb.append(threadName).append(y.toSimpleString()).append(" loaded and injected").append(LINE_SEPARATOR); sb.append(threadName).append(y.toSimpleString()).append(" load and inject").append(LINE_SEPARATOR);
}); });
} }
//----------------- init ----------------- //----------------- init -----------------
@@ -362,7 +362,7 @@ public abstract class NodeServer {
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
y.getService().init(y.getConf()); y.getService().init(y.getConf());
long e = System.currentTimeMillis() - s; long e = System.currentTimeMillis() - s;
if (slist != null) slist.add(new StringBuilder().append(threadName).append(y.toSimpleString()).append(" loaded and inited ").append(e).append(" ms").append(LINE_SEPARATOR).toString()); 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());
} finally { } finally {
clds.countDown(); clds.countDown();
} }
@@ -403,7 +403,7 @@ public abstract class NodeServer {
Transport first = transports.get(0); Transport first = transports.get(0);
GroupInfo ginfo = application.findGroupInfo(first.getName()); GroupInfo ginfo = application.findGroupInfo(first.getName());
Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(), Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs); ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
synchronized (application.resourceFactory) { synchronized (application.resourceFactory) {
transport = application.resourceFactory.find(groupid, Transport.class); transport = application.resourceFactory.find(groupid, Transport.class);
if (transport == null) { if (transport == null) {
@@ -429,7 +429,7 @@ public abstract class NodeServer {
Set<InetSocketAddress> addrs = ginfo.copyAddrs(); Set<InetSocketAddress> addrs = ginfo.copyAddrs();
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> "); if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(), transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(),
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs); ginfo.getSubprotocol(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
application.resourceFactory.register(group, transport); application.resourceFactory.register(group, transport);
} }
return transport; return transport;

View File

@@ -13,6 +13,7 @@ import org.redkale.net.sncp.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* SNCP Server节点的配置Server
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -61,7 +62,7 @@ public class NodeSncpServer extends NodeServer {
List<SncpServlet> servlets = sncpServer.getSncpServlets(); List<SncpServlet> servlets = sncpServer.getSncpServlets();
Collections.sort(servlets); Collections.sort(servlets);
for (SncpServlet en : servlets) { for (SncpServlet en : servlets) {
if (sb != null) sb.append(threadName).append(" Loaded ").append(en).append(LINE_SEPARATOR); if (sb != null) sb.append(threadName).append(" Load ").append(en).append(LINE_SEPARATOR);
} }
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString()); if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
} }

View File

@@ -1,12 +1,12 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="UTF-8"><title>Document</title> <meta charset="UTF-8"><title>接口文档(apidoc生成)</title>
<style type="text/css"> <style type="text/css">
body {text-align: center;margin:auto;} body {text-align: center;margin:auto;}
a{text-decoration: none;} a{text-decoration: none;}
.table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;} .table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;}
.table td,.table th{padding: 0.4rem 1.2rem 0.4rem 1.2rem;border: 1px solid #aaa;} .table td,.table th{padding: 0.2rem 0.8rem 0.2rem 0.8rem;border: 1px solid #aaa;}
.table td {text-align: left;} .table td {text-align: left;}
.s {font-size: 0.8rem; vertical-align: middle;} .s {font-size: 0.8rem; vertical-align: middle;}
.subtable {border-spacing: 0;border: 0;margin:0;} .subtable {border-spacing: 0;border: 0;margin:0;}
@@ -25,13 +25,19 @@
html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">'); html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">');
html.push('<br/><br/><table class="table" align="center">'); html.push('<br/><br/><table class="table" align="center">');
for (var i = 0; i < jsoncontent.servers.length; i++) { for (var i = 0; i < jsoncontent.servers.length; i++) {
for (var j = 0; j < jsoncontent.servers[i].servlets.length; j++) { var servlets = jsoncontent.servers[i].servlets;
var servlet = jsoncontent.servers[i].servlets[j]; if (servlets.length && (servlets[0].comment || "").indexOf("【") === 0) {
servlets.sort(function (a, b) {
return a.comment > b.comment ? -1 : (a.comment == b.comment ? 0 : 1);
});
}
for (var j = 0; j < servlets.length; j++) {
var servlet = servlets[j];
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>'); 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 colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>'); html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
for (var k = 0; k < servlet.actions.length; k++) { for (var k = 0; k < servlet.mappings.length; k++) {
var action = servlet.actions[k]; var action = servlet.mappings[k];
html.push(' <tr>'); html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>'); html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>'); html.push('<td>' + action.comment + '</td>');
@@ -47,15 +53,22 @@
if (param.name == '&') { if (param.name == '&') {
paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>'); paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>');
} else { } else {
var c = ' style="font-weight:bold;"'; var w = param.required ? "font-weight:bold;" : "";
if (param.src == "HEADER") c = ' style="color:red;font-weight:bold;"'; var c = ' style="' + w + '"';
if (param.src == "COOKIE") c = ' style="color:blue;font-weight:bold;"'; if (param.src == "HEADER") c = ' style="color:red;' + w + '"';
if (param.src == "COOKIE") c = ' style="color:blue;' + w + '"';
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>'); paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
} }
} }
paramshtml.push('</table>'); paramshtml.push('</table>');
html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>'); html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>');
html.push('<td>' + action.result.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</td>'); var rs = [];
rs.push(action.result.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""));
var results = action.results || [];
for (var r = 0; r < results.length; r++) {
rs.push('<a href="#' + results[r].replace('[]', '') + '">' + results[r].replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</a>');
}
html.push('<td>' + rs.join("<br/>") + '</td>');
html.push('</tr>'); html.push('</tr>');
} }
} }
@@ -66,8 +79,20 @@
html.push(' <tr><td colspan="5"><table class="typetable">'); html.push(' <tr><td colspan="5"><table class="typetable">');
for (var fieldname in classmap[type]) { for (var fieldname in classmap[type]) {
var field = classmap[type][fieldname]; var field = classmap[type][fieldname];
var t = field.type.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""); var t = field.type.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\$/g, ".").replace(/([a-zA-Z0-9_\$]+\.)+/g, "");
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + (field.comment || '') + '</td></tr>'); if (t == 'boolean' || t == 'short' || t == 'int' || t == 'long' || t == 'float' || t == 'double'
|| t == 'boolean[]' || t == 'short[]' || t == 'int[]' || t == 'long[]' || t == 'float[]' || t == 'double[]') {
t = '<font color=blue>' + t + '</font>';
} else if (t == 'String' || t == 'String[]' || t == 'LongRange' || t.indexOf('Map&lt;') === 0) {
t = '<font color=red>' + t + '</font>';
}
var c = (field.comment || '');
if (field.primary) {
c = '【主键】 ' + c;
} else if (!field.updatable) {
c = '【只读】 ' + c;
}
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + c + '</td></tr>');
} }
html.push(' </table></td></tr>'); html.push(' </table></td></tr>');
} }
@@ -78,7 +103,7 @@
</script> </script>
<script> <script>
var jsoncontent = ${content}; var jsoncontent = '${content}'; //这里必须要用单引号引起来
document.write(createhtml(jsoncontent)); document.write(createhtml(jsoncontent));
</script> </script>
</body> </body>

View File

@@ -9,9 +9,9 @@ import java.lang.reflect.*;
import java.util.*; import java.util.*;
/** /**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组. * 数组的序列化操作类 <br>
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有采用int存储。 * 对象数组的反序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 * 支持一定程度的泛型。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -28,10 +28,15 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
private final Class componentClass; private final Class componentClass;
private final Decodeable<Reader, T> decoder; protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
private final Object lock = new Object();
public ArrayDecoder(final ConvertFactory factory, final Type type) { public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try {
if (type instanceof GenericArrayType) { if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType(); Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t; this.componentType = t instanceof TypeVariable ? Object.class : t;
@@ -47,12 +52,29 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
} }
factory.register(type, this); factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType); this.decoder = factory.loadDecoder(this.componentType);
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
} }
@Override @Override
public T[] convertFrom(Reader in) { public T[] convertFrom(Reader in) {
final int len = in.readArrayB(); final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null; 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 Decodeable<Reader, T> localdecoder = this.decoder;
final List<T> result = new ArrayList(); final List<T> result = new ArrayList();
if (len == Reader.SIGN_NOLENGTH) { if (len == Reader.SIGN_NOLENGTH) {

View File

@@ -8,9 +8,9 @@ package org.redkale.convert;
import java.lang.reflect.*; import java.lang.reflect.*;
/** /**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组. * 数组的序列化操作类 <br>
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有必要采用int存储。 * 对象数组的序列化不包含int[]、long[]这样的primitive class数组。 <br>
* 支持一定程度的泛型。 * 支持一定程度的泛型。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -29,8 +29,13 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
private final Encodeable<Writer, Object> encoder; private final Encodeable<Writer, Object> encoder;
private boolean inited = false;
private final Object lock = new Object();
public ArrayEncoder(final ConvertFactory factory, final Type type) { public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try {
if (type instanceof GenericArrayType) { if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType(); Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t; this.componentType = t instanceof TypeVariable ? Object.class : t;
@@ -42,6 +47,12 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
factory.register(type, this); factory.register(type, this);
this.encoder = factory.loadEncoder(this.componentType); this.encoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder(); this.anyEncoder = factory.getAnyEncoder();
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
} }
@Override @Override
@@ -55,6 +66,17 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
out.writeArrayE(); out.writeArrayE();
return; return;
} }
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeArrayB(value.length); out.writeArrayB(value.length);
final Type comp = this.componentType; final Type comp = this.componentType;
boolean first = true; boolean first = true;

View File

@@ -11,9 +11,8 @@ import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
/** /**
* 对象集合的反序列化. * Collection的反序列化操作类 <br>
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。 * 支持一定程度的泛型。 <br>
* 支持一定程度的泛型。
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -30,10 +29,15 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
protected Creator<Collection<T>> creator; protected Creator<Collection<T>> creator;
private final Decodeable<Reader, T> decoder; protected final Decodeable<Reader, T> decoder;
private boolean inited = false;
private final Object lock = new Object();
public CollectionDecoder(final ConvertFactory factory, final Type type) { public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try {
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type; final ParameterizedType pt = (ParameterizedType) type;
this.componentType = pt.getActualTypeArguments()[0]; this.componentType = pt.getActualTypeArguments()[0];
@@ -43,12 +47,29 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
} else { } else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")"); throw new ConvertException("collectiondecoder not support the type (" + type + ")");
} }
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
} }
@Override @Override
public Collection<T> convertFrom(Reader in) { public Collection<T> convertFrom(Reader in) {
final int len = in.readArrayB(); final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null; 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 Decodeable<Reader, T> localdecoder = this.decoder;
final Collection<T> result = this.creator.create(); final Collection<T> result = this.creator.create();
if (len == Reader.SIGN_NOLENGTH) { if (len == Reader.SIGN_NOLENGTH) {

View File

@@ -9,11 +9,12 @@ import java.lang.reflect.*;
import java.util.Collection; import java.util.Collection;
/** /**
* 对象集合的序列化. * Collection的序列化操作类 <br>
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。 * 支持一定程度的泛型。 <br>
* 支持一定程度的泛型。 *
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
* @param <T> 序列化的集合元素类型 * @param <T> 序列化的集合元素类型
*/ */
@@ -24,8 +25,13 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
private final Encodeable<Writer, Object> encoder; private final Encodeable<Writer, Object> encoder;
private boolean inited = false;
private final Object lock = new Object();
public CollectionEncoder(final ConvertFactory factory, final Type type) { public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try {
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) { if (t instanceof TypeVariable) {
@@ -36,6 +42,12 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
} else { } else {
this.encoder = factory.getAnyEncoder(); this.encoder = factory.getAnyEncoder();
} }
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
} }
@Override @Override
@@ -49,6 +61,17 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
out.writeArrayE(); out.writeArrayE();
return; return;
} }
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeArrayB(value.size()); out.writeArrayB(value.size());
boolean first = true; boolean first = true;
for (Object v : value) { for (Object v : value) {

View File

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

View File

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

View File

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

View File

@@ -17,6 +17,7 @@ import org.redkale.convert.ext.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 序列化模块的工厂类用于注册自定义的序列化类型获取Convert
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -91,6 +92,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance); this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance);
this.register(Pattern.class, PatternSimpledCoder.instance); this.register(Pattern.class, PatternSimpledCoder.instance);
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance); this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
this.register(AsyncHandler.class, AsyncHandlerSimpledCoder.instance);
this.register(URL.class, URLSimpledCoder.instance); this.register(URL.class, URLSimpledCoder.instance);
this.register(URI.class, URISimpledCoder.instance); this.register(URI.class, URISimpledCoder.instance);
//--------------------------------------------------------- //---------------------------------------------------------
@@ -104,6 +106,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(double[].class, DoubleArraySimpledCoder.instance); this.register(double[].class, DoubleArraySimpledCoder.instance);
this.register(String[].class, StringArraySimpledCoder.instance); this.register(String[].class, StringArraySimpledCoder.instance);
//--------------------------------------------------------- //---------------------------------------------------------
this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class));
this.register(HttpCookie.class, new Creator<HttpCookie>() { this.register(HttpCookie.class, new Creator<HttpCookie>() {
@Override @Override
@Creator.ConstructorParameters({"name", "value"}) @Creator.ConstructorParameters({"name", "value"})

View File

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

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 字段的反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -88,6 +89,6 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
@Override @Override
public String toString() { public String toString() {
return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + decoder + '}'; return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + (decoder == null ? null : decoder.getClass().getName()) + '}';
} }
} }

View File

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

View File

@@ -9,6 +9,7 @@ import java.lang.reflect.*;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 字段的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -81,6 +82,6 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
@Override @Override
public String toString() { public String toString() {
return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + encoder + '}'; return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + (encoder == null ? null : encoder.getClass().getName()) + '}';
} }
} }

View File

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

View File

@@ -11,8 +11,11 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* Map的反序列化操作类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
* @param <K> Map key的数据类型 * @param <K> Map key的数据类型
* @param <V> Map value的数据类型 * @param <V> Map value的数据类型
@@ -28,12 +31,17 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
protected Creator<Map<K, V>> creator; protected Creator<Map<K, V>> creator;
private final Decodeable<Reader, K> keyDecoder; protected final Decodeable<Reader, K> keyDecoder;
private final Decodeable<Reader, V> valueDecoder; protected final Decodeable<Reader, V> valueDecoder;
private boolean inited = false;
private final Object lock = new Object();
public MapDecoder(final ConvertFactory factory, final Type type) { public MapDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try {
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type; final ParameterizedType pt = (ParameterizedType) type;
this.keyType = pt.getActualTypeArguments()[0]; this.keyType = pt.getActualTypeArguments()[0];
@@ -45,10 +53,27 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
} else { } else {
throw new ConvertException("mapdecoder not support the type (" + type + ")"); throw new ConvertException("mapdecoder not support the type (" + type + ")");
} }
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
} }
@Override @Override
public Map<K, V> convertFrom(Reader in) { public Map<K, V> convertFrom(Reader in) {
if (this.keyDecoder == null || this.valueDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
final int len = in.readMapB(); final int len = in.readMapB();
if (len == Reader.SIGN_NULL) return null; if (len == Reader.SIGN_NULL) return null;
final Map<K, V> result = this.creator.create(); final Map<K, V> result = this.creator.create();

View File

@@ -10,6 +10,7 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
/** /**
* Map的序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -27,8 +28,13 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
private final Encodeable<Writer, V> valencoder; private final Encodeable<Writer, V> valencoder;
private boolean inited = false;
private final Object lock = new Object();
public MapEncoder(final ConvertFactory factory, final Type type) { public MapEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try {
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments(); final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
this.keyencoder = factory.loadEncoder(pt[0]); this.keyencoder = factory.loadEncoder(pt[0]);
@@ -37,6 +43,12 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
this.keyencoder = factory.getAnyEncoder(); this.keyencoder = factory.getAnyEncoder();
this.valencoder = factory.getAnyEncoder(); this.valencoder = factory.getAnyEncoder();
} }
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
} }
@Override @Override
@@ -46,6 +58,18 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
out.writeNull(); out.writeNull();
return; return;
} }
if (this.keyencoder == null || this.valencoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
out.writeMapB(values.size()); out.writeMapB(values.size());
boolean first = true; boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) { for (Map.Entry<K, V> en : values.entrySet()) {

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,6 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Attribute; import org.redkale.util.Attribute;
/** /**
* 序列化的数据输出流
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -11,6 +11,7 @@ import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 以ByteBuffer为数据载体的BsonReader
* *
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *

View File

@@ -7,8 +7,10 @@ package org.redkale.convert.bson;
import java.nio.*; import java.nio.*;
import java.util.function.*; import java.util.function.*;
import org.redkale.util.Utility;
/** /**
* 以ByteBuffer为数据载体的BsonWriter
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -78,20 +80,14 @@ public class BsonByteBufferWriter extends BsonWriter {
if (!buffer.hasRemaining()) { if (!buffer.hasRemaining()) {
buffer.flip(); buffer.flip();
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
this.index++; this.index++;
} }
int len = buffer.remaining(); int len = buffer.remaining();
int size = 0; int size = 0;
while (len < byteLength) { while (len < byteLength) {
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
len += buffer.remaining(); len += buffer.remaining();
size++; size++;
} }

View File

@@ -15,21 +15,21 @@ import org.redkale.util.*;
/** /**
* <blockquote><pre> * <blockquote><pre>
* BSON协议格式: * BSON协议格式:
* 1). 基本数据类型: 直接转换成byte[] * 1) 基本数据类型: 直接转换成byte[]
* 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 * 2) SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
* 3). String: length(4 bytes) + byte[](utf8); * 3) String: length(4 bytes) + byte[](utf8);
* 4). 数组: length(4 bytes) + byte[]... * 4) 数组: length(4 bytes) + byte[]...
* 5). Object: * 5) Object:
* 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名) * 1 realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
* 2. 空字符串(SmallString) * 2 空字符串(SmallString)
* 3. SIGN_OBJECTB 标记位值固定为0xBB (short) * 3 SIGN_OBJECTB 标记位值固定为0xBB (short)
* 4. 循环字段值: * 4 循环字段值:
* 4.1 SIGN_HASNEXT 标记位值固定为1 (byte) * 4.1 SIGN_HASNEXT 标记位值固定为1 (byte)
* 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object * 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object
* 4.3 字段名 (SmallString) * 4.3 字段名 (SmallString)
* 4.4 字段的值Object * 4.4 字段的值Object
* 5. SIGN_NONEXT 标记位值固定为0 (byte) * 5 SIGN_NONEXT 标记位值固定为0 (byte)
* 6. SIGN_OBJECTE 标记位值固定为0xEE (short) * 6 SIGN_OBJECTE 标记位值固定为0xEE (short)
* *
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>

View File

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

View File

@@ -5,13 +5,13 @@
*/ */
package org.redkale.convert.bson; package org.redkale.convert.bson;
import java.util.function.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import static org.redkale.convert.Reader.SIGN_NULL; import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.convert.ext.*; import org.redkale.convert.ext.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* BSON数据源
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -42,19 +42,7 @@ public class BsonReader extends Reader {
} }
public static ObjectPool<BsonReader> createPool(int max) { public static ObjectPool<BsonReader> createPool(int max) {
return new ObjectPool<BsonReader>(max, new Creator<BsonReader>() { return new ObjectPool<>(max, (Object... params) -> new BsonReader(), null, (t) -> t.recycle());
@Override
public BsonReader create(Object... params) {
return new BsonReader();
}
}, null, new Predicate<BsonReader>() {
@Override
public boolean test(BsonReader t) {
return t.recycle();
}
});
} }
public BsonReader(byte[] bytes) { public BsonReader(byte[] bytes) {

View File

@@ -6,7 +6,6 @@
package org.redkale.convert.bson; package org.redkale.convert.bson;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.function.Predicate;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.util.*; import org.redkale.util.*;
@@ -28,19 +27,7 @@ public class BsonWriter extends Writer {
protected boolean tiny; protected boolean tiny;
public static ObjectPool<BsonWriter> createPool(int max) { public static ObjectPool<BsonWriter> createPool(int max) {
return new ObjectPool<BsonWriter>(max, new Creator<BsonWriter>() { return new ObjectPool<>(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());
@Override
public BsonWriter create(Object... params) {
return new BsonWriter();
}
}, null, new Predicate<BsonWriter>() {
@Override
public boolean test(BsonWriter t) {
return t.recycle();
}
});
} }
public byte[] toArray() { public byte[] toArray() {
@@ -82,6 +69,7 @@ public class BsonWriter extends Writer {
* 扩充指定长度的缓冲区 * 扩充指定长度的缓冲区
* *
* @param len 扩容长度 * @param len 扩容长度
*
* @return 固定0 * @return 固定0
*/ */
protected int expand(int len) { protected int expand(int len) {

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

@@ -11,6 +11,7 @@ import org.redkale.convert.*;
import static org.redkale.convert.Reader.*; import static org.redkale.convert.Reader.*;
/** /**
* 以ByteBuffer为数据载体的JsonReader <br>
* *
* 只支持UTF-8格式 * 只支持UTF-8格式
* *

View File

@@ -13,6 +13,7 @@ import org.redkale.convert.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 以ByteBuffer为数据载体的JsonWriter
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -84,20 +85,14 @@ public class JsonByteBufferWriter extends JsonWriter {
if (!buffer.hasRemaining()) { if (!buffer.hasRemaining()) {
buffer.flip(); buffer.flip();
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
this.index++; this.index++;
} }
int len = buffer.remaining(); int len = buffer.remaining();
int size = 0; int size = 0;
while (len < byteLength) { while (len < byteLength) {
buffer = supplier.get(); buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; this.buffers = Utility.append(this.buffers, buffer);
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
len += buffer.remaining(); len += buffer.remaining();
size++; size++;
} }

View File

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

View File

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

View File

@@ -17,42 +17,60 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* 服务器上下文对象
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class Context { public class Context {
private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Charset UTF8 = Charset.forName("UTF-8");
//服务启动时间
protected final long serverStartTime; protected final long serverStartTime;
//Server的线程池
protected final ExecutorService executor; protected final ExecutorService executor;
//ByteBuffer的容量默认8K
protected final int bufferCapacity; protected final int bufferCapacity;
//ByteBuffer对象池
protected final ObjectPool<ByteBuffer> bufferPool; protected final ObjectPool<ByteBuffer> bufferPool;
//Response对象池
protected final ObjectPool<Response> responsePool; protected final ObjectPool<Response> responsePool;
//服务的根Servlet
protected final PrepareServlet prepare; protected final PrepareServlet prepare;
//服务的监听地址
private final InetSocketAddress address; private final InetSocketAddress address;
//字符集
protected final Charset charset; protected final Charset charset;
//请求内容的大小上限, 默认64K
protected final int maxbody; protected final int maxbody;
//IO读取的超时时间
protected final int readTimeoutSecond; protected final int readTimeoutSecond;
//IO写入的超时时间
protected final int writeTimeoutSecond; protected final int writeTimeoutSecond;
//日志Logger
protected final Logger logger; protected final Logger logger;
//BSON操作工厂
protected final BsonFactory bsonFactory; protected final BsonFactory bsonFactory;
//JSON操作工厂
protected final JsonFactory jsonFactory; protected final JsonFactory jsonFactory;
//监控对象
protected final WatchFactory watch; protected final WatchFactory watch;
public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool, public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,

View File

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

View File

@@ -14,6 +14,9 @@ import java.util.logging.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 根Servlet 一个Server只能存在一个根Servlet
*
* 用于分发Request请求
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -13,6 +13,7 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
* 协议底层Server
* *
* <p> 详情见: https://redkale.org * <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx

View File

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

View File

@@ -10,6 +10,7 @@ import java.nio.channels.CompletionHandler;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
/** /**
* 协议响应对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -29,6 +30,8 @@ public abstract class Response<C extends Context, R extends Request<C>> {
private boolean inited = true; private boolean inited = true;
protected Object output; //输出的结果对象
protected BiConsumer<R, Response<C, R>> recycleListener; protected BiConsumer<R, Response<C, R>> recycleListener;
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() { private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
@@ -54,29 +57,26 @@ public abstract class Response<C extends Context, R extends Request<C>> {
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() { private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
@Override @Override
public void completed(Integer result, ByteBuffer[] attachments) { public void completed(final Integer result, final ByteBuffer[] attachments) {
int index = -1; int index = -1;
for (int i = 0; i < attachments.length; i++) { for (int i = 0; i < attachments.length; i++) {
if (attachments[i].hasRemaining()) { if (attachments[i].hasRemaining()) {
index = i; index = i;
break; break;
} else {
context.offerBuffer(attachments[i]);
} }
} }
if (index == 0) { if (index >= 0) {
channel.write(attachments, attachments, this); channel.write(attachments, index, attachments.length - index, attachments, this);
} else if (index > 0) {
ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index];
System.arraycopy(attachments, index, newattachs, 0, newattachs.length);
channel.write(newattachs, newattachs, this);
} else { } else {
for (ByteBuffer attachment : attachments) {
context.offerBuffer(attachment);
}
finish(); finish();
} }
} }
@Override @Override
public void failed(Throwable exc, ByteBuffer[] attachments) { public void failed(Throwable exc, final ByteBuffer[] attachments) {
for (ByteBuffer attachment : attachments) { for (ByteBuffer attachment : attachments) {
context.offerBuffer(attachment); context.offerBuffer(attachment);
} }
@@ -113,6 +113,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
} }
recycleListener = null; recycleListener = null;
} }
this.output = null;
request.recycle(); request.recycle();
if (channel != null) { if (channel != null) {
if (keepAlive) { if (keepAlive) {
@@ -143,6 +144,19 @@ public abstract class Response<C extends Context, R extends Request<C>> {
this.recycleListener = recycleListener; this.recycleListener = recycleListener;
} }
public Object getOutput() {
return output;
}
/**
* 是否已关闭
*
* @return boolean
*/
public boolean isClosed() {
return !this.inited;
}
public void finish() { public void finish() {
this.finish(false); this.finish(false);
} }
@@ -153,6 +167,17 @@ public abstract class Response<C extends Context, R extends Request<C>> {
this.context.responsePool.offer(this); this.context.responsePool.offer(this);
} }
public void finish(final byte[] bs) {
if (this.context.bufferCapacity == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
buffer.flip();
this.finish(buffer);
} else {
this.finish(ByteBuffer.wrap(bs));
}
}
public void finish(ByteBuffer buffer) { public void finish(ByteBuffer buffer) {
this.channel.write(buffer, buffer, finishHandler); this.channel.write(buffer, buffer, finishHandler);
} }

View File

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

View File

@@ -44,7 +44,7 @@ public final class Transport {
protected final String name; //即<group>的name属性 protected final String name; //即<group>的name属性
protected final String kind; //即<group>的kind属性 protected final String subprotocol; //即<group>的subprotocol属性
protected final boolean tcp; protected final boolean tcp;
@@ -62,16 +62,16 @@ public final class Transport {
protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>(); 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, WatchFactory watch, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) { final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this(name, DEFAULT_PROTOCOL, watch, kind, transportBufferPool, transportChannelGroup, clientAddress, addresses); this(name, DEFAULT_PROTOCOL, watch, 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, WatchFactory watch, String subprotocol, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) { final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this.name = name; this.name = name;
this.watch = watch; this.watch = watch;
this.kind = kind == null ? "" : kind.trim(); this.subprotocol = subprotocol == null ? "" : subprotocol.trim();
this.protocol = protocol; this.protocol = protocol;
this.tcp = "TCP".equalsIgnoreCase(protocol); this.tcp = "TCP".equalsIgnoreCase(protocol);
this.group = transportChannelGroup; this.group = transportChannelGroup;
@@ -83,14 +83,17 @@ public final class Transport {
public Transport(final Collection<Transport> transports) { public Transport(final Collection<Transport> transports) {
Transport first = null; Transport first = null;
List<String> tmpgroup = new ArrayList<>(); List<String> tmpgroup = new ArrayList<>();
if (transports != null) {
for (Transport t : transports) { for (Transport t : transports) {
if (first == null) first = t; if (first == null) first = t;
tmpgroup.add(t.name); tmpgroup.add(t.name);
} }
}
if (first == null) throw new NullPointerException("Collection<Transport> is null or empty");
//必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name //必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name
this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";")); this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";"));
this.watch = first.watch; this.watch = first.watch;
this.kind = first.kind; this.subprotocol = first.subprotocol;
this.protocol = first.protocol; this.protocol = first.protocol;
this.tcp = "TCP".equalsIgnoreCase(first.protocol); this.tcp = "TCP".equalsIgnoreCase(first.protocol);
this.group = first.group; this.group = first.group;
@@ -118,8 +121,8 @@ public final class Transport {
return name; return name;
} }
public String getKind() { public String getSubprotocol() {
return kind; return subprotocol;
} }
public void close() { public void close() {

View File

@@ -8,8 +8,11 @@ package org.redkale.net;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
* 协议处理的自定义线程类
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public class WorkThread extends Thread { public class WorkThread extends Thread {

View File

@@ -1,18 +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.net.http;
/**
*
* <p>
* 详情见: https://redkale.org
*
* @deprecated 使用 org.redkale.net.http.HttpBaseServlet 代替
* @see org.redkale.net.http.HttpBaseServlet
* @author zhangjx
*/
public abstract class BasedHttpServlet extends HttpBaseServlet {
}

View File

@@ -66,8 +66,8 @@ public abstract class HttpBaseServlet extends HttpServlet {
} }
/** /**
* 配合 &#64;WebAction 使用。 * 配合 &#64;WebMapping 使用。
* 用于对&#64;WebAction方法中参数描述 * 用于对&#64;WebMapping方法中参数描述
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -89,6 +89,8 @@ public abstract class HttpBaseServlet extends HttpServlet {
ParamSourceType src() default ParamSourceType.PARAMETER; //参数来源类型 ParamSourceType src() default ParamSourceType.PARAMETER; //参数来源类型
int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制 int radix() default 10; //转换数字byte/short/int/long时所用的进制数 默认10进制
boolean required() default true; //参数是否必传
} }
@Documented @Documented
@@ -99,6 +101,34 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebParam[] value(); WebParam[] value();
} }
/**
* 使用 WebMapping 替代。
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Deprecated
@Documented
@Target({METHOD})
@Retention(RUNTIME)
protected @interface WebAction {
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 {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
}
/** /**
* 配合 HttpBaseServlet 使用。 * 配合 HttpBaseServlet 使用。
* 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式 * 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式
@@ -111,7 +141,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
@Documented @Documented
@Target({METHOD}) @Target({METHOD})
@Retention(RUNTIME) @Retention(RUNTIME)
protected @interface WebAction { protected @interface WebMapping {
int actionid() default 0; int actionid() default 0;
@@ -121,13 +151,16 @@ public abstract class HttpBaseServlet extends HttpServlet {
String comment() default ""; //备注描述 String comment() default ""; //备注描述
boolean inherited() default true; //是否能被继承, 当 HttpBaseServlet 被继承后该方法是否能被子类继承
String result() default "Object"; //输出结果的数据类型 String result() default "Object"; //输出结果的数据类型
Class[] results() default {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
} }
/** /**
* 配合 HttpBaseServlet 使用。 * 配合 HttpBaseServlet 使用。
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值timeout=15秒)。 * 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
* 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。 * 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。
* *
* <p> * <p>
@@ -145,10 +178,10 @@ public abstract class HttpBaseServlet extends HttpServlet {
* *
* @return 超时秒数 * @return 超时秒数
*/ */
int timeout() default 15; 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 { public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException {
return true; return true;
@@ -157,7 +190,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
@Override @Override
public final void execute(HttpRequest request, HttpResponse response) throws IOException { public final void execute(HttpRequest request, HttpResponse response) throws IOException {
if (!preExecute(request, response)) return; if (!preExecute(request, response)) return;
for (Map.Entry<String, Entry> en : actions) { for (Map.Entry<String, Entry> en : mappings) {
if (request.getRequestURI().startsWith(en.getKey())) { if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue(); Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) { if (!entry.checkMethod(request.getMethod())) {
@@ -165,9 +198,9 @@ public abstract class HttpBaseServlet extends HttpServlet {
return; return;
} }
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) { if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
if (entry.cachetimeout > 0) {//有缓存设置 if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI()); CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效 if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status); response.setStatus(ce.status);
response.setContentType(ce.contentType); response.setContentType(ce.contentType);
response.finish(ce.getBuffers()); response.finish(ce.getBuffers());
@@ -188,13 +221,13 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebServlet ws = this.getClass().getAnnotation(WebServlet.class); WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = ""; if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load(); HashMap<String, Entry> map = load();
this.actions = new Map.Entry[map.size()]; this.mappings = new Map.Entry[map.size()];
int i = -1; int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) { 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 //必须要倒排序, /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 final void postDestroy(HttpContext context, AnyValue config) {
@@ -219,8 +252,12 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebServlet module = this.getClass().getAnnotation(WebServlet.class); WebServlet module = this.getClass().getAnnotation(WebServlet.class);
final int serviceid = module == null ? 0 : module.moduleid(); final int serviceid = module == null ? 0 : module.moduleid();
final HashMap<String, Entry> map = new HashMap<>(); final HashMap<String, Entry> map = new HashMap<>();
Set<String> nameset = new HashSet<>(); HashMap<String, Class> nameset = new HashMap<>();
for (final Method method : this.getClass().getMethods()) { final Class selfClz = this.getClass();
Class clz = this.getClass();
do {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (final Method method : clz.getMethods()) {
//----------------------------------------------- //-----------------------------------------------
String methodname = method.getName(); String methodname = method.getName();
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue; if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
@@ -233,15 +270,22 @@ public abstract class HttpBaseServlet extends HttpServlet {
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue; 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); final WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue; if (mapping == null && action == null) continue;
final int actionid = action.actionid(); final boolean inherited = mapping == null ? action.inherited() : mapping.inherited();
final String name = action.url().trim(); if (!inherited && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = mapping == null ? action.actionid() : mapping.actionid();
if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")"); final String name = mapping == null ? action.url().trim() : mapping.url().trim();
nameset.add(name); final String[] methods = mapping == null ? action.methods() : mapping.methods();
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method))); if (nameset.containsKey(name)) {
if (nameset.get(name) != clz) continue;
throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebMapping.class.getSimpleName() + "(" + name + ")");
} }
nameset.put(name, clz);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, methods, method, createHttpServlet(method)));
}
} while ((clz = clz.getSuperclass()) != HttpBaseServlet.class);
return map; return map;
} }
@@ -335,9 +379,9 @@ public abstract class HttpBaseServlet extends HttpServlet {
this.servlet = servlet; this.servlet = servlet;
this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null; this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null;
HttpCacheable hc = method.getAnnotation(HttpCacheable.class); HttpCacheable hc = method.getAnnotation(HttpCacheable.class);
this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000; this.cacheseconds = hc == null ? 0 : hc.seconds() * 1000;
this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null; this.cache = cacheseconds > 0 ? new ConcurrentHashMap() : null;
this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> { this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus(); int status = response.getStatus();
if (status != 200) return null; if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers); CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
@@ -362,7 +406,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
public final ConcurrentHashMap<String, CacheEntry> cache; public final ConcurrentHashMap<String, CacheEntry> cache;
public final int cachetimeout; public final int cacheseconds;
public final boolean ignore; public final boolean ignore;

View File

@@ -16,6 +16,7 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* HTTP服务的上下文对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -17,6 +17,8 @@ import org.redkale.util.*;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* HTTP Servlet的总入口请求在HttpPrepareServlet中进行分流。 <br>
* 一个HttpServer只有一个HttpPrepareServlet 用于管理所有HttpServlet。 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -89,6 +91,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
} }
//找不到匹配的HttpServlet则使用静态资源HttpResourceServlet
if (servlet == null) servlet = this.resourceHttpServlet; if (servlet == null) servlet = this.resourceHttpServlet;
servlet.execute(request, response); servlet.execute(request, response);
} catch (Exception e) { } catch (Exception e) {
@@ -97,6 +100,14 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param prefix url前缀
* @param conf 配置信息
* @param mappings 匹配规则
*/
@Override @Override
public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) { public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) {
if (prefix == null) prefix = ""; if (prefix == null) prefix = "";
@@ -107,12 +118,12 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix
} }
} }
synchronized (allMapStrings) { synchronized (allMapStrings) { //需要整段锁住
for (String mapping : mappings) { for (String mapping : mappings) {
if (mapping == null) continue; if (mapping == null) continue;
if (!prefix.toString().isEmpty()) mapping = prefix + mapping; if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
if (contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式)) if (Utility.contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
if (mapping.charAt(0) != '^') mapping = '^' + mapping; if (mapping.charAt(0) != '^') mapping = '^' + mapping;
if (mapping.endsWith("/*")) { if (mapping.endsWith("/*")) {
mapping = mapping.substring(0, mapping.length() - 1) + ".*"; mapping = mapping.substring(0, mapping.length() - 1) + ".*";
@@ -141,22 +152,22 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} }
} }
private static boolean contains(String string, char... values) { /**
if (string == null) return false; * 设置静态资源HttpServlet
for (char ch : Utility.charArray(string)) { *
for (char ch2 : values) { * @param servlet HttpServlet
if (ch == ch2) return true; */
}
}
return false;
}
public void setResourceServlet(HttpServlet servlet) { public void setResourceServlet(HttpServlet servlet) {
if (servlet != null) { if (servlet != null) {
this.resourceHttpServlet = servlet; this.resourceHttpServlet = servlet;
} }
} }
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() { public HttpServlet getResourceServlet() {
return this.resourceHttpServlet; return this.resourceHttpServlet;
} }

View File

@@ -22,7 +22,7 @@ import org.redkale.util.ByteArray;
* 例如简单的翻页查询 <br> * 例如简单的翻页查询 <br>
* /pipes/record/query/offset:0/limit:20 <br> * /pipes/record/query/offset:0/limit:20 <br>
* 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br> * 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br>
* 获取行数: int limit = request.getRequstURIPath("limit:", 10); * 获取行数: int limit = request.getRequstURIPath("limit:", 10); <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -236,7 +236,7 @@ public class HttpRequest extends Request<HttpContext> {
* @return 地址 * @return 地址
*/ */
public SocketAddress getRemoteAddress() { public SocketAddress getRemoteAddress() {
return this.channel.getRemoteAddress(); return this.channel == null || !this.channel.isOpen() ? null : this.channel.getRemoteAddress();
} }
/** /**
@@ -352,7 +352,7 @@ public class HttpRequest extends Request<HttpContext> {
public String getSessionid(boolean create) { public String getSessionid(boolean create) {
String sessionid = getCookie(SESSIONID_NAME, null); String sessionid = getCookie(SESSIONID_NAME, null);
if (create && (sessionid == null || sessionid.isEmpty())) { if (create && (sessionid == null || sessionid.isEmpty())) {
sessionid = ((HttpContext) context).createSessionid(); sessionid = context.createSessionid();
this.newsessionid = sessionid; this.newsessionid = sessionid;
} }
return sessionid; return sessionid;
@@ -368,6 +368,18 @@ public class HttpRequest extends Request<HttpContext> {
return newsessionid; return newsessionid;
} }
/**
* 指定值更新sessionid
*
* @param newsessionid 新sessionid值
*
* @return 新的sessionid值
*/
public String changeSessionid(String newsessionid) {
this.newsessionid = newsessionid == null ? context.createSessionid() : newsessionid.trim();
return newsessionid;
}
/** /**
* 使sessionid失效 * 使sessionid失效
*/ */
@@ -500,6 +512,123 @@ public class HttpRequest extends Request<HttpContext> {
return requestURI.substring(requestURI.lastIndexOf('/') + 1); 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再对"/"进行分隔 * 从prefix之后截取getRequestURI再对"/"进行分隔
@@ -1109,17 +1238,18 @@ public class HttpRequest extends Request<HttpContext> {
* @return Flipper翻页对象 * @return Flipper翻页对象
*/ */
public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) { 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); org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name);
if (flipper == null) { if (flipper == null) {
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
int limit = getRequstURIPath("limit:", maxLimit); int limit = getRequstURIPath("limit:", maxLimit);
int offset = getRequstURIPath("offset:", 0); int offset = getRequstURIPath("offset:", 0);
String sort = getRequstURIPath("sort:", ""); String sort = getRequstURIPath("sort:", "");
if (limit > 0) flipper = new org.redkale.source.Flipper(limit, offset, 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); flipper.setLimit(maxLimit);
} }
if (flipper != null || !needcreate) return flipper; if (flipper != null || !needcreate) return flipper;
if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT;
return new org.redkale.source.Flipper(maxLimit); return new org.redkale.source.Flipper(maxLimit);
} }
} }

View File

@@ -18,6 +18,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue; import org.redkale.util.AnyValue;
/** /**
* 静态资源HttpServlet
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -14,6 +14,7 @@ import java.nio.file.*;
import java.text.*; import java.text.*;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
@@ -21,9 +22,9 @@ import org.redkale.util.AnyValue.Entry;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。 * Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。 <br>
* 同时提供发送json的系列接口: public void finishJson(Type type, Object obj) * 同时提供发送json的系列接口: public void finishJson(Type type, Object obj) <br>
* Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。 * Redkale提倡http+json的接口风格 所以主要输出的数据格式为json 同时提供异步接口。 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -184,14 +185,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @return HttpResponse * @return HttpResponse
*/ */
public HttpResponse addCookie(HttpCookie... cookies) { public HttpResponse addCookie(HttpCookie... cookies) {
if (this.cookies == null) { this.cookies = Utility.append(this.cookies, cookies);
this.cookies = cookies;
} else {
HttpCookie[] news = new HttpCookie[this.cookies.length + cookies.length];
System.arraycopy(this.cookies, 0, news, 0, this.cookies.length);
System.arraycopy(cookies, 0, news, this.cookies.length, cookies.length);
this.cookies = news;
}
return this; return this;
} }
@@ -203,21 +197,30 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @return HttpResponse * @return HttpResponse
*/ */
public HttpResponse addCookie(Collection<HttpCookie> cookies) { public HttpResponse addCookie(Collection<HttpCookie> cookies) {
if (cookies == null || cookies.isEmpty()) return this; this.cookies = Utility.append(this.cookies, cookies);
if (this.cookies == null) {
this.cookies = cookies.toArray(new HttpCookie[cookies.size()]);
} else {
HttpCookie[] news = new HttpCookie[this.cookies.length + cookies.size()];
System.arraycopy(this.cookies, 0, news, 0, this.cookies.length);
int i = this.cookies.length;
for (HttpCookie cookie : cookies) {
news[i++] = cookie;
}
this.cookies = news;
}
return this; return this;
} }
/**
* 创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出
*
* @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);
});
}
/** /**
* 将对象以JSON格式输出 * 将对象以JSON格式输出
* *
@@ -225,6 +228,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final Object obj) { public void finishJson(final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = obj;
finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), obj)); finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), obj));
} }
@@ -236,6 +240,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final JsonConvert convert, final Object obj) { public void finishJson(final JsonConvert convert, final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = obj;
finish(convert.convertTo(context.getBufferSupplier(), obj)); finish(convert.convertTo(context.getBufferSupplier(), obj));
} }
@@ -247,6 +252,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final Type type, final Object obj) { public void finishJson(final Type type, final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
this.output = obj;
finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), type, obj)); finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), type, obj));
} }
@@ -259,6 +265,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final JsonConvert convert, final Type type, final Object obj) { public void finishJson(final JsonConvert convert, final Type type, final Object obj) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = obj;
finish(convert.convertTo(context.getBufferSupplier(), type, obj)); finish(convert.convertTo(context.getBufferSupplier(), type, obj));
} }
@@ -269,6 +276,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final Object... objs) { public void finishJson(final Object... objs) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = objs;
finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), objs)); finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), objs));
} }
@@ -279,6 +287,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final org.redkale.service.RetResult ret) { public void finishJson(final org.redkale.service.RetResult ret) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = ret;
if (ret != null && !ret.isSuccess()) { if (ret != null && !ret.isSuccess()) {
this.header.addValue("retcode", String.valueOf(ret.getRetcode())); this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
this.header.addValue("retinfo", ret.getRetinfo()); this.header.addValue("retinfo", ret.getRetinfo());
@@ -294,6 +303,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/ */
public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret) { public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret) {
this.contentType = "text/plain; charset=utf-8"; this.contentType = "text/plain; charset=utf-8";
if (this.recycleListener != null) this.output = ret;
if (ret != null && !ret.isSuccess()) { if (ret != null && !ret.isSuccess()) {
this.header.addValue("retcode", String.valueOf(ret.getRetcode())); this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
this.header.addValue("retinfo", ret.getRetinfo()); this.header.addValue("retinfo", ret.getRetinfo());
@@ -301,35 +311,13 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
finish(convert.convertTo(context.getBufferSupplier(), ret)); finish(convert.convertTo(context.getBufferSupplier(), ret));
} }
/**
* 将对象以JavaScript格式输出
*
* @param var js变量名
* @param result 输出对象
*/
public void finishJsResult(String var, Object result) {
this.contentType = "application/javascript; charset=utf-8";
finish("var " + var + " = " + request.getJsonConvert().convertTo(result) + ";");
}
/**
* 将对象以JavaScript格式输出
*
* @param jsonConvert 指定的JsonConvert
* @param var js变量名
* @param result 输出对象
*/
public void finishJsResult(JsonConvert jsonConvert, String var, Object result) {
this.contentType = "application/javascript; charset=utf-8";
finish("var " + var + " = " + jsonConvert.convertTo(result) + ";");
}
/** /**
* 将指定字符串以响应结果输出 * 将指定字符串以响应结果输出
* *
* @param obj 输出内容 * @param obj 输出内容
*/ */
public void finish(String obj) { public void finish(String obj) {
if (this.recycleListener != null) this.output = obj;
if (obj == null || obj.isEmpty()) { if (obj == null || obj.isEmpty()) {
final ByteBuffer headbuf = createHeader(); final ByteBuffer headbuf = createHeader();
headbuf.flip(); headbuf.flip();
@@ -389,6 +377,23 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
super.finish(buffer404.duplicate()); super.finish(buffer404.duplicate());
} }
/**
* 将指定byte[]按响应结果输出
*
* @param bs 输出内容
*/
@Override
public void finish(final byte[] bs) {
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按响应结果输出 * 将指定ByteBuffer按响应结果输出
* *
@@ -473,7 +478,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param attachment 异步回调参数 * @param attachment 异步回调参数
* @param handler 异步回调函数 * @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.headsended) {
if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining(); if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining();
ByteBuffer headbuf = createHeader(); ByteBuffer headbuf = createHeader();
@@ -812,7 +817,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
this.bufferHandler = bufferHandler; this.bufferHandler = bufferHandler;
} }
protected final class TransferFileHandler implements CompletionHandler<Integer, ByteBuffer> { protected final class TransferFileHandler implements AsyncHandler<Integer, ByteBuffer> {
private final AsynchronousFileChannel filechannel; private final AsynchronousFileChannel filechannel;

View File

@@ -16,6 +16,7 @@ import org.redkale.util.*;
import org.redkale.watch.WatchFactory; import org.redkale.watch.WatchFactory;
/** /**
* Http服务器
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -37,24 +38,88 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
super.init(config); super.init(config);
} }
/**
* 获取静态资源HttpServlet
*
* @return HttpServlet
*/
public HttpServlet getResourceServlet() {
return ((HttpPrepareServlet) this.prepare).resourceHttpServlet;
}
/**
* 添加HttpServlet
*
* @param prefix url前缀
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) { public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, prefix, null, mappings); this.prepare.addServlet(servlet, prefix, null, mappings);
return this; return this;
} }
/**
* 添加HttpServlet
*
* @param servlet HttpServlet
* @param mappings 匹配规则
*
* @return HttpServer
*/
public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) { public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) {
this.prepare.addServlet(servlet, null, null, mappings); this.prepare.addServlet(servlet, null, null, mappings);
return this; 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); this.prepare.addServlet(servlet, prefix, conf, mappings);
return this;
} }
/**
* 添加RestHttpServlet
*
* @param <S> Service
* @param <T> RestHttpServlet
* @param name Service的资源名
* @param serviceType Service的类型
* @param service Service对象
* @param baseServletClass RestHttpServlet基类
* @param prefix url前缀
*
* @return RestHttpServlet
*/
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(String name, Class<S> serviceType, S service, Class<T> baseServletClass, String prefix) { 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); return addRestServlet(name, serviceType, service, baseServletClass, prefix, null);
} }
/**
* 添加RestHttpServlet
*
* @param <S> Service
* @param <T> RestHttpServlet
* @param name Service的资源名
* @param serviceType Service的类型
* @param service Service对象
* @param baseServletClass RestHttpServlet基类
* @param prefix url前缀
* @param conf 配置信息
*
* @return RestHttpServlet
*/
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet( 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) { final String name, Class<S> serviceType, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) {
RestHttpServlet servlet = null; RestHttpServlet servlet = null;

View File

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

View File

@@ -15,6 +15,7 @@ import java.util.regex.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
/** /**
* HTTP的文件上传请求的上下文对象
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -77,10 +78,21 @@ public final class MultiContext {
return null; return null;
} }
/**
* 判断请求是否包含上传文件
*
* @return boolean
*/
public boolean isMultipart() { public boolean isMultipart() {
return this.boundary != null; return this.boundary != null;
} }
/**
* 获取上传文件信息列表
*
* @return Iterable
* @throws IOException IOException
*/
public Iterable<MultiPart> parts() throws IOException { public Iterable<MultiPart> parts() throws IOException {
if (!isMultipart()) return emptyIterable; if (!isMultipart()) return emptyIterable;
final String boundarystr = "--" + this.boundary; final String boundarystr = "--" + this.boundary;

View File

@@ -82,7 +82,7 @@ public final class Rest {
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class); final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class); final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class);
final String cacheDesc = Type.getDescriptor(HttpBaseServlet.HttpCacheable.class); final String cacheDesc = Type.getDescriptor(HttpBaseServlet.HttpCacheable.class);
final String actionDesc = Type.getDescriptor(HttpBaseServlet.WebAction.class); final String mappingDesc = Type.getDescriptor(HttpBaseServlet.WebMapping.class);
final String webparamDesc = Type.getDescriptor(HttpBaseServlet.WebParam.class); final String webparamDesc = Type.getDescriptor(HttpBaseServlet.WebParam.class);
final String webparamsDesc = Type.getDescriptor(HttpBaseServlet.WebParams.class); final String webparamsDesc = Type.getDescriptor(HttpBaseServlet.WebParams.class);
final String sourcetypeDesc = Type.getDescriptor(HttpBaseServlet.ParamSourceType.class); final String sourcetypeDesc = Type.getDescriptor(HttpBaseServlet.ParamSourceType.class);
@@ -122,7 +122,7 @@ public final class Rest {
AsmMethodVisitor mv; AsmMethodVisitor mv;
AnnotationVisitor av0; AnnotationVisitor av0;
Map<String, Object> classMap = new LinkedHashMap<>(); Map<String, Object> classMap = new LinkedHashMap<>();
List<Map<String, Object>> actionMaps = new ArrayList<>(); List<Map<String, Object>> mappingMaps = new ArrayList<>();
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null); cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
{ //RestDynamic { //RestDynamic
@@ -175,7 +175,7 @@ public final class Rest {
final List<MappingEntry> entrys = new ArrayList<>(); final List<MappingEntry> entrys = new ArrayList<>();
final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>(); final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
//获取所有可以转换成WebMapping的方法
for (final Method method : serviceType.getMethods()) { for (final Method method : serviceType.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue; if (Modifier.isStatic(method.getModifiers())) continue;
Class[] extypes = method.getExceptionTypes(); Class[] extypes = method.getExceptionTypes();
@@ -207,7 +207,9 @@ public final class Rest {
} }
} }
} }
if (entrys.isEmpty()) return null; //没有可WebAction的方法 if (entrys.isEmpty()) return null; //没有可WebMapping的方法
//将每个Service可转换的方法生成HttpServlet对应的WebMapping方法
for (final MappingEntry entry : entrys) { for (final MappingEntry entry : entrys) {
final Method method = entry.mappingMethod; final Method method = entry.mappingMethod;
final Class returnType = method.getReturnType(); final Class returnType = method.getReturnType();
@@ -221,9 +223,9 @@ public final class Rest {
av0 = mv.visitAnnotation(authDesc, true); av0 = mv.visitAnnotation(authDesc, true);
av0.visitEnd(); av0.visitEnd();
} }
if (entry.cachetimeout > 0) { //设置 HttpCacheable if (entry.cacheseconds > 0) { //设置 HttpCacheable
av0 = mv.visitAnnotation(cacheDesc, true); av0 = mv.visitAnnotation(cacheDesc, true);
av0.visit("timeout", entry.cachetimeout); av0.visit("seconds", entry.cacheseconds);
av0.visitEnd(); av0.visitEnd();
} }
@@ -254,14 +256,15 @@ public final class Rest {
final int maxStack = 3 + params.length; final int maxStack = 3 + params.length;
List<int[]> varInsns = new ArrayList<>(); List<int[]> varInsns = new ArrayList<>();
int maxLocals = 4; int maxLocals = 4;
final String jsvar = entry.jsvar.isEmpty() ? null : entry.jsvar;
int argIndex = 0; int argIndex = 0;
List<Object[]> paramlist = new ArrayList<>(); List<Object[]> paramlist = new ArrayList<>();
//解析方法中的每个参数
for (final Parameter param : params) { for (final Parameter param : params) {
final Class ptype = param.getType(); final Class ptype = param.getType();
String n = null; String n = null;
String comment = ""; String comment = "";
boolean required = true;
int radix = 10; int radix = 10;
RestHeader annhead = param.getAnnotation(RestHeader.class); RestHeader annhead = param.getAnnotation(RestHeader.class);
@@ -297,6 +300,7 @@ public final class Rest {
RestParam annpara = param.getAnnotation(RestParam.class); RestParam annpara = param.getAnnotation(RestParam.class);
if (annpara != null) radix = annpara.radix(); if (annpara != null) radix = annpara.radix();
if (annpara != null) comment = annpara.comment(); if (annpara != null) comment = annpara.comment();
if (annpara != null) required = annpara.required();
if (n == null) n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name(); if (n == null) n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name();
if (n == null && ptype == userType) n = "&"; //用户类型特殊处理 if (n == null && ptype == userType) n = "&"; //用户类型特殊处理
if (n == null) { if (n == null) {
@@ -312,12 +316,12 @@ public final class Rest {
&& (entry.name.startsWith("find") || entry.name.startsWith("delete")) && params.length == 1) { && (entry.name.startsWith("find") || entry.name.startsWith("delete")) && params.length == 1) {
if (ptype.isPrimitive() || ptype == String.class) n = "#"; if (ptype.isPrimitive() || ptype == String.class) n = "#";
} }
paramlist.add(new Object[]{param, n, ptype, radix, comment, annpara, annsid, annaddr, annhead, anncookie}); paramlist.add(new Object[]{param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie});
} }
Map<String, Object> actionMap = new LinkedHashMap<>(); Map<String, Object> mappingMap = new LinkedHashMap<>();
{ { // 设置 Annotation
//设置 WebAction //设置 WebMapping
boolean reqpath = false; boolean reqpath = false;
for (Object[] ps : paramlist) { for (Object[] ps : paramlist) {
if ("#".equals((String) ps[1])) { if ("#".equals((String) ps[1])) {
@@ -325,7 +329,7 @@ public final class Rest {
break; break;
} }
} }
av0 = mv.visitAnnotation(actionDesc, true); av0 = mv.visitAnnotation(mappingDesc, true);
String url = "/" + defmodulename.toLowerCase() + "/" + entry.name + (reqpath ? "/" : ""); String url = "/" + defmodulename.toLowerCase() + "/" + entry.name + (reqpath ? "/" : "");
av0.visit("url", url); av0.visit("url", url);
av0.visit("actionid", entry.actionid); av0.visit("actionid", entry.actionid);
@@ -341,22 +345,22 @@ public final class Rest {
av0.visit("result", grt == returnType ? returnType.getName() : String.valueOf(grt)); av0.visit("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
av0.visitEnd(); av0.visitEnd();
actionMap.put("url", url); mappingMap.put("url", url);
actionMap.put("auth", entry.auth); mappingMap.put("auth", entry.auth);
actionMap.put("cachetimeout", entry.cachetimeout); mappingMap.put("cachetimeout", entry.cacheseconds);
actionMap.put("actionid", entry.actionid); mappingMap.put("actionid", entry.actionid);
actionMap.put("comment", entry.comment); mappingMap.put("comment", entry.comment);
actionMap.put("methods", entry.methods); mappingMap.put("methods", entry.methods);
actionMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt)); mappingMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
} }
{ { // 设置 Annotation
av0 = mv.visitAnnotation(webparamsDesc, true); av0 = mv.visitAnnotation(webparamsDesc, true);
AnnotationVisitor av1 = av0.visitArray("value"); AnnotationVisitor av1 = av0.visitArray("value");
//设置 WebParam //设置 WebParam
for (Object[] ps : paramlist) { //{param, n, ptype, radix, comment, annpara, annsid, annaddr, annhead, anncookie} for (Object[] ps : paramlist) { //{param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie}
final boolean ishead = ((RestHeader) ps[8]) != null; //是否取getHeader 而不是 getParameter final boolean ishead = ((RestHeader) ps[9]) != null; //是否取getHeader 而不是 getParameter
final boolean iscookie = ((RestCookie) ps[9]) != null; //是否取getCookie final boolean iscookie = ((RestCookie) ps[10]) != null; //是否取getCookie
AnnotationVisitor av2 = av1.visitAnnotation(null, webparamDesc); AnnotationVisitor av2 = av1.visitAnnotation(null, webparamDesc);
av2.visit("name", (String) ps[1]); av2.visit("name", (String) ps[1]);
@@ -365,30 +369,40 @@ public final class Rest {
av2.visitEnum("src", sourcetypeDesc, ishead ? HttpBaseServlet.ParamSourceType.HEADER.name() av2.visitEnum("src", sourcetypeDesc, ishead ? HttpBaseServlet.ParamSourceType.HEADER.name()
: (iscookie ? HttpBaseServlet.ParamSourceType.COOKIE.name() : HttpBaseServlet.ParamSourceType.PARAMETER.name())); : (iscookie ? HttpBaseServlet.ParamSourceType.COOKIE.name() : HttpBaseServlet.ParamSourceType.PARAMETER.name()));
av2.visit("comment", (String) ps[4]); av2.visit("comment", (String) ps[4]);
av2.visit("required", (Boolean) ps[5]);
av2.visitEnd(); av2.visitEnd();
} }
av1.visitEnd(); av1.visitEnd();
av0.visitEnd(); av0.visitEnd();
} }
List<Map<String, Object>> paramMaps = new ArrayList<>(); List<Map<String, Object>> paramMaps = new ArrayList<>();
//获取每个参数的值
boolean hasAsyncHandler = false;
for (Object[] ps : paramlist) { for (Object[] ps : paramlist) {
Map<String, Object> paramMap = new LinkedHashMap<>(); Map<String, Object> paramMap = new LinkedHashMap<>();
String pname = (String) ps[1]; //参数名 String pname = (String) ps[1]; //参数名
Class ptype = (Class) ps[2]; Class ptype = (Class) ps[2]; //参数类型
int radix = (Integer) ps[3]; int radix = (Integer) ps[3];
String comment = (String) ps[4]; String comment = (String) ps[4];
RestParam annpara = (RestParam) ps[5]; boolean required = (Boolean) ps[5];
RestSessionid annsid = (RestSessionid) ps[6]; RestParam annpara = (RestParam) ps[6];
RestAddress annaddr = (RestAddress) ps[7]; RestSessionid annsid = (RestSessionid) ps[7];
RestHeader annhead = (RestHeader) ps[8]; RestAddress annaddr = (RestAddress) ps[8];
RestCookie anncookie = (RestCookie) ps[9]; RestHeader annhead = (RestHeader) ps[9];
RestCookie anncookie = (RestCookie) ps[10];
final boolean ishead = annhead != null; //是否取getHeader 而不是 getParameter final boolean ishead = annhead != null; //是否取getHeader 而不是 getParameter
final boolean iscookie = anncookie != null; //是否取getCookie final boolean iscookie = anncookie != null; //是否取getCookie
paramMap.put("name", pname); paramMap.put("name", pname);
paramMap.put("type", ptype.getName()); paramMap.put("type", ptype.getName());
if (annsid != null) { //HttpRequest.getSessionid(true|false) if (ptype == AsyncHandler.class) { //HttpResponse.createAsyncHandler()
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "()Lorg/redkale/util/AsyncHandler;", false);
mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals});
hasAsyncHandler = true;
} else if (annsid != null) { //HttpRequest.getSessionid(true|false)
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0); mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0);
mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false);
@@ -720,227 +734,125 @@ public final class Rest {
mv.visitVarInsn(ins[0], ins[1]); mv.visitVarInsn(ins[0], ins[1]);
} }
mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false); mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false);
if (returnType == void.class) { if (hasAsyncHandler) {
mv.visitInsn(RETURN);
} else if (returnType == void.class) {
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false); mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
} else if (returnType == boolean.class) { } else if (returnType == boolean.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Z)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == byte.class) { } else if (returnType == byte.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == short.class) { } else if (returnType == short.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == char.class) { } else if (returnType == char.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(C)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == int.class) { } else if (returnType == int.class) {
mv.visitVarInsn(ISTORE, maxLocals); mv.visitVarInsn(ISTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ILOAD, maxLocals); mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ILOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == float.class) { } else if (returnType == float.class) {
mv.visitVarInsn(FSTORE, maxLocals); mv.visitVarInsn(FSTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(FLOAD, maxLocals); mv.visitVarInsn(FLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(F)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(FLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == long.class) { } else if (returnType == long.class) {
mv.visitVarInsn(LSTORE, maxLocals); mv.visitVarInsn(LSTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(LLOAD, maxLocals); mv.visitVarInsn(LLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(J)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(LLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals += 2; maxLocals += 2;
} else if (returnType == double.class) { } else if (returnType == double.class) {
mv.visitVarInsn(DSTORE, maxLocals); mv.visitVarInsn(DSTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(DLOAD, maxLocals); mv.visitVarInsn(DLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(D)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(DLOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals += 2; maxLocals += 2;
} else if (returnType == String.class) { } else if (returnType == String.class) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (returnType == File.class) { } else if (returnType == File.class) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/io/File;)V", false);
} else {
throw new RuntimeException(method + " cannot set return Type (java.io.File) to jsvar");
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (RetResult.class.isAssignableFrom(returnType)) { } else if (RetResult.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (RestOutput.class.isAssignableFrom(returnType)) { } else if (RestOutput.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + restoutputDesc + ")V", false); mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + restoutputDesc + ")V", false);
} else {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJsResult", "(" + respDesc + "Ljava/lang/String;" + restoutputDesc + ")V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面 } else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} else { } else {
mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ASTORE, maxLocals);
if (jsvar == null) {
mv.visitVarInsn(ALOAD, 2); //response mv.visitVarInsn(ALOAD, 2); //response
mv.visitVarInsn(ALOAD, maxLocals); mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(Ljava/lang/Object;)V", false); mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(Ljava/lang/Object;)V", false);
} else {
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(jsvar);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJsResult", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
}
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
maxLocals++; maxLocals++;
} }
mv.visitMaxs(maxStack, maxLocals); mv.visitMaxs(maxStack, maxLocals);
actionMap.put("params", paramMaps); mappingMap.put("params", paramMaps);
actionMaps.add(actionMap); mappingMaps.add(mappingMap);
} // end for each } // end for each
for (String attrname : restAttributes.keySet()) { for (String attrname : restAttributes.keySet()) {
@@ -948,7 +860,7 @@ public final class Rest {
fv.visitEnd(); fv.visitEnd();
} }
classMap.put("actions", actionMaps); classMap.put("mappings", mappingMaps);
{ //toString函数 { //toString函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
@@ -1014,10 +926,8 @@ public final class Rest {
this.methods = mapping.methods(); this.methods = mapping.methods();
this.auth = mapping.auth(); this.auth = mapping.auth();
this.actionid = mapping.actionid(); this.actionid = mapping.actionid();
this.cachetimeout = mapping.cachetimeout(); this.cacheseconds = mapping.cacheseconds();
//this.contentType = mapping.contentType();
this.comment = mapping.comment(); this.comment = mapping.comment();
this.jsvar = mapping.jsvar();
} }
public final Method mappingMethod; public final Method mappingMethod;
@@ -1034,10 +944,7 @@ public final class Rest {
public final int actionid; public final int actionid;
public final int cachetimeout; public final int cacheseconds;
//public final String contentType;
public final String jsvar;
@RestMapping() @RestMapping()
void mapping() { //用于获取Mapping 默认值 void mapping() { //用于获取Mapping 默认值

View File

@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestCookie { 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

@@ -22,9 +22,24 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestHeader { 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

@@ -23,22 +23,17 @@ public abstract class RestHttpServlet<T> extends HttpBaseServlet {
response.finishJson(output); response.finishJson(output);
return; return;
} }
if (output.getContentType() != null) response.setContentType(output.getContentType());
response.addHeader(output.getHeaders()); response.addHeader(output.getHeaders());
response.addCookie(output.getCookies()); response.addCookie(output.getCookies());
if (output.getResult() instanceof File) { if (output.getResult() instanceof File) {
response.finish((File) output.getResult()); response.finish((File) output.getResult());
} else if (output.getResult() instanceof String) {
response.finish((String) output.getResult());
} else { } else {
response.finishJson(output.getResult()); 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());
}
} }

View File

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

View File

@@ -23,6 +23,8 @@ public class RestOutput<T> {
private List<HttpCookie> cookies; private List<HttpCookie> cookies;
private String contentType;
private T result; private T result;
public RestOutput() { public RestOutput() {
@@ -58,6 +60,14 @@ public class RestOutput<T> {
this.cookies = cookies; this.cookies = cookies;
} }
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public T getResult() { public T getResult() {
return result; return result;
} }

View File

@@ -10,9 +10,11 @@ import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 只能依附在Service类的方法的参数上, name值不能是'&#38;' *
* name='#'表示截取uri最后一段 * 依附在RestService类的方法的参数上 <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 * name='&#38;' 表示当前用户 <br>
* name='#'表示截取uri最后一段 <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
@@ -24,9 +26,35 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface RestParam { public @interface RestParam {
String name(); //参数名 //name='&'表示当前用户;
/**
* 参数名 <br>
* name='&#38;'表示当前用户; <br>
* name='#'表示截取uri最后一段; <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <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;
String comment() default ""; //备注描述 /**
* 参数是否必传
*
* @return boolean
*/
boolean required() default true;
/**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -10,7 +10,9 @@ import java.lang.annotation.*;
/** /**
* 功能同JSR 315 (java-servlet 3.0) 规范中的 @WebInitParam * 功能同JSR 315 (java-servlet 3.0) 规范中的 @WebInitParam
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
*/ */
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
@@ -18,9 +20,24 @@ import java.lang.annotation.*;
@Documented @Documented
public @interface WebInitParam { public @interface WebInitParam {
/**
* 参数名
*
* @return String
*/
String name(); String name();
/**
* 参数值
*
* @return String
*/
String value(); String value();
/**
* 参数描述
*
* @return String
*/
String description() default ""; String description() default "";
} }

View File

@@ -21,15 +21,45 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface WebServlet { public @interface WebServlet {
/**
* HttpServlet资源名
*
* @return String
*/
String name() default ""; String name() default "";
/**
* 是否自动添加url前缀, 对应application.xml中servlets节点的path属性
*
* @return boolean
*/
boolean repair() default true; boolean repair() default true;
/**
* url匹配规则
*
* @return String[]
*/
String[] value() default {}; String[] value() default {};
/**
* 模块ID一个HttpServlet尽量只有提供一个模块的服务
*
* @return int
*/
int moduleid() default 0; int moduleid() default 0;
/**
* 参数
*
* @return WebInitParam[]
*/
WebInitParam[] initParams() default {}; WebInitParam[] initParams() default {};
String comment() default ""; //备注描述 /**
* 备注描述
*
* @return String
*/
String comment() default "";
} }

View File

@@ -11,6 +11,7 @@ import java.net.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.util.Comment;
/** /**
* <blockquote><pre> * <blockquote><pre>
@@ -22,15 +23,13 @@ import org.redkale.net.*;
* 1.3 onConnected WebSocket成功连接后在准备接收数据前回调此方法。 * 1.3 onConnected WebSocket成功连接后在准备接收数据前回调此方法。
* 1.4 onMessage/onFragment+ WebSocket接收到消息后回调此消息类方法。 * 1.4 onMessage/onFragment+ WebSocket接收到消息后回调此消息类方法。
* 1.5 onClose WebSocket被关闭后回调此方法。 * 1.5 onClose WebSocket被关闭后回调此方法。
* * 普通模式下 以上方法都应该被重载。
* 此模式下 以上方法都应该被重载。
* *
* 2) 原始二进制模式: 此模式有别于HTML5规范可以视为原始的TCP连接。通常用于音频视频通讯场景。其流程顺序如下: * 2) 原始二进制模式: 此模式有别于HTML5规范可以视为原始的TCP连接。通常用于音频视频通讯场景。其流程顺序如下:
* 2.1 onOpen 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。 * 2.1 onOpen 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。
* 2.2 createGroupid 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。 * 2.2 createGroupid 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。
* 2.3 onRead WebSocket成功连接后回调此方法 由此方法处理原始的TCP连接 同时业务代码去控制WebSocket的关闭。 * 2.3 onRead WebSocket成功连接后回调此方法 由此方法处理原始的TCP连接 需要业务代码去控制WebSocket的关闭。
* * 二进制模式下 以上方法都应该被重载。
* 此模式下 以上方法都应该被重载。
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -39,24 +38,28 @@ import org.redkale.net.*;
*/ */
public abstract class WebSocket { public abstract class WebSocket {
//消息不合法 @Comment("消息不合法")
public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2 public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2
//ws已经关闭 @Comment("WebSocket已经关闭")
public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4 public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4
//socket的buffer不合法 @Comment("Socket的buffer不合法")
public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8 public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8
//ws发送消息异常 @Comment("WebSocket发送消息异常")
public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16 public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16
@Comment("WebSocketEngine实例不存在")
public static final int RETCODE_ENGINE_NULL = 1 << 5; //32 public static final int RETCODE_ENGINE_NULL = 1 << 5; //32
@Comment("WebSocketNode实例不存在")
public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64 public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64
@Comment("WebSocket组为空, 表示无WebSocket连接")
public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128 public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128
@Comment("WebSocket已离线")
public static final int RETCODE_WSOFFLINE = 1 << 8; //256 public static final int RETCODE_WSOFFLINE = 1 << 8; //256
WebSocketRunner _runner; //不可能为空 WebSocketRunner _runner; //不可能为空
@@ -82,9 +85,10 @@ public abstract class WebSocket {
//---------------------------------------------------------------- //----------------------------------------------------------------
/** /**
* 发送消息体, 包含二进制/文本 * 给自身发送消息体, 包含二进制/文本
* *
* @param packet WebSocketPacket * @param packet WebSocketPacket
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(WebSocketPacket packet) { public final int send(WebSocketPacket packet) {
@@ -95,9 +99,10 @@ public abstract class WebSocket {
} }
/** /**
* 发送单一的文本消息 * 给自身发送单一的文本消息
* *
* @param text 不可为空 * @param text 不可为空
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(String text) { public final int send(String text) {
@@ -105,10 +110,11 @@ public abstract class WebSocket {
} }
/** /**
* 发送文本消息 * 给自身发送文本消息
* *
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(String text, boolean last) { public final int send(String text, boolean last) {
@@ -133,9 +139,10 @@ public abstract class WebSocket {
} }
/** /**
* 发送单一的二进制消息 * 给自身发送单一的二进制消息
* *
* @param data byte[] * @param data byte[]
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(byte[] data) { public final int send(byte[] data) {
@@ -143,10 +150,11 @@ public abstract class WebSocket {
} }
/** /**
* 发送二进制消息 * 给自身发送二进制消息
* *
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(byte[] data, boolean last) { public final int send(byte[] data, boolean last) {
@@ -154,10 +162,11 @@ public abstract class WebSocket {
} }
/** /**
* 发送消息, 消息类型是String或byte[] * 给自身发送消息, 消息类型是String或byte[]
* *
* @param message 不可为空, 只能是String或者byte[] * @param message 不可为空, 只能是String或者byte[]
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码 * @return 0表示成功 非0表示错误码
*/ */
public final int send(Serializable message, boolean last) { public final int send(Serializable message, boolean last) {
@@ -170,6 +179,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, String text) { public final int sendEachMessage(Serializable groupid, String text) {
@@ -181,6 +191,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, byte[] data) { public final int sendEachMessage(Serializable groupid, byte[] data) {
@@ -193,6 +204,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, String text, boolean last) { public final int sendEachMessage(Serializable groupid, String text, boolean last) {
@@ -205,6 +217,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) { public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) {
@@ -216,6 +229,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, String text) { public final int sendRecentMessage(Serializable groupid, String text) {
@@ -227,6 +241,7 @@ public abstract class WebSocket {
* *
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, byte[] data) { public final int sendRecentMessage(Serializable groupid, byte[] data) {
@@ -239,6 +254,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param text 不可为空 * @param text 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, String text, boolean last) { public final int sendRecentMessage(Serializable groupid, String text, boolean last) {
@@ -251,6 +267,7 @@ public abstract class WebSocket {
* @param groupid groupid * @param groupid groupid
* @param data 不可为空 * @param data 不可为空
* @param last 是否最后一条 * @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常 * @return 为0表示成功 其他值表示异常
*/ */
public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) { public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) {
@@ -272,9 +289,10 @@ public abstract class WebSocket {
} }
/** /**
* 获取在线用户的节点地址列表 * 获取指定groupid在线用户的节点地址列表
* *
* @param groupid groupid * @param groupid groupid
*
* @return 地址列表 * @return 地址列表
*/ */
protected final Collection<InetSocketAddress> getOnlineNodes(Serializable groupid) { protected final Collection<InetSocketAddress> getOnlineNodes(Serializable groupid) {
@@ -282,9 +300,10 @@ public abstract class WebSocket {
} }
/** /**
* 获取在线用户的详细连接信息 * 获取指定groupid在线用户的详细连接信息
* *
* @param groupid groupid * @param groupid groupid
*
* @return 地址集合 * @return 地址集合
*/ */
protected final Map<InetSocketAddress, List<String>> getOnlineRemoteAddress(Serializable groupid) { protected final Map<InetSocketAddress, List<String>> getOnlineRemoteAddress(Serializable groupid) {
@@ -296,6 +315,7 @@ public abstract class WebSocket {
* *
* @param <T> 属性值的类型 * @param <T> 属性值的类型
* @param name 属性名 * @param name 属性名
*
* @return 属性值 * @return 属性值
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -308,6 +328,7 @@ public abstract class WebSocket {
* *
* @param <T> 属性值的类型 * @param <T> 属性值的类型
* @param name 属性名 * @param name 属性名
*
* @return 属性值 * @return 属性值
*/ */
public final <T> T removeAttribute(String name) { public final <T> T removeAttribute(String name) {
@@ -374,6 +395,7 @@ public abstract class WebSocket {
* 获取指定groupid的WebSocketGroup, 没有返回null * 获取指定groupid的WebSocketGroup, 没有返回null
* *
* @param groupid groupid * @param groupid groupid
*
* @return WebSocketGroup * @return WebSocketGroup
*/ */
protected final WebSocketGroup getWebSocketGroup(Serializable groupid) { protected final WebSocketGroup getWebSocketGroup(Serializable groupid) {
@@ -394,6 +416,7 @@ public abstract class WebSocket {
* 返回sessionid, null表示连接不合法或异常,默认实现是request.getSessionid(false),通常需要重写该方法 * 返回sessionid, null表示连接不合法或异常,默认实现是request.getSessionid(false),通常需要重写该方法
* *
* @param request HttpRequest * @param request HttpRequest
*
* @return sessionid * @return sessionid
*/ */
public Serializable onOpen(final HttpRequest request) { public Serializable onOpen(final HttpRequest request) {

View File

@@ -8,7 +8,6 @@ package org.redkale.net.http;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.nio.*; import java.nio.*;
import java.nio.channels.*;
import java.security.*; import java.security.*;
import java.util.*; import java.util.*;
import java.util.logging.*; import java.util.logging.*;
@@ -23,7 +22,8 @@ import org.redkale.util.*;
* WebSocketServlet * WebSocketServlet
* | * |
* | * |
* WebSocketEngine &#38; WebSocketNode * WebSocketEngine
* WebSocketNode
* / \ * / \
* / \ * / \
* / \ * / \
@@ -41,8 +41,10 @@ import org.redkale.util.*;
*/ */
public abstract class WebSocketServlet extends HttpServlet { public abstract class WebSocketServlet extends HttpServlet {
@Comment("WebScoket服务器给客户端进行ping操作的间隔时间, 单位: 秒")
public static final String WEBPARAM__LIVEINTERVAL = "liveinterval"; public static final String WEBPARAM__LIVEINTERVAL = "liveinterval";
@Comment("WebScoket服务器给客户端进行ping操作的默认间隔时间, 单位: 秒")
public static final int DEFAILT_LIVEINTERVAL = 60; public static final int DEFAILT_LIVEINTERVAL = 60;
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
@@ -57,7 +59,7 @@ public abstract class WebSocketServlet extends HttpServlet {
} }
} }
//是否用于二进制流传输 @Comment("是否用于二进制流传输")
protected final boolean wsbinary = getClass().getAnnotation(WebSocketBinary.class) != null; protected final boolean wsbinary = getClass().getAnnotation(WebSocketBinary.class) != null;
@Resource(name = "$") @Resource(name = "$")
@@ -125,7 +127,7 @@ public abstract class WebSocketServlet extends HttpServlet {
response.setHeader("Connection", "Upgrade"); response.setHeader("Connection", "Upgrade");
response.addHeader("Upgrade", "websocket"); response.addHeader("Upgrade", "websocket");
response.addHeader("Sec-WebSocket-Accept", key); response.addHeader("Sec-WebSocket-Accept", key);
response.sendBody((ByteBuffer) null, null, new CompletionHandler<Integer, Void>() { response.sendBody((ByteBuffer) null, null, new AsyncHandler<Integer, Void>() {
@Override @Override
public void completed(Integer result, Void attachment) { public void completed(Integer result, Void attachment) {

View File

@@ -43,6 +43,10 @@ public final class SncpClient {
protected final Attribute[] paramAttrs; // 为null表示无RpcCall处理index=0固定为null, 其他为参数标记的RpcCall回调方法 protected final Attribute[] paramAttrs; // 为null表示无RpcCall处理index=0固定为null, 其他为参数标记的RpcCall回调方法
protected final int handlerFuncParamIndex;
protected final int handlerAttachParamIndex;
protected final int addressTargetParamIndex; protected final int addressTargetParamIndex;
protected final int addressSourceParamIndex; protected final int addressSourceParamIndex;
@@ -60,16 +64,24 @@ public final class SncpClient {
Annotation[][] anns = method.getParameterAnnotations(); Annotation[][] anns = method.getParameterAnnotations();
int targetAddrIndex = -1; int targetAddrIndex = -1;
int sourceAddrIndex = -1; int sourceAddrIndex = -1;
int handlerAttachIndex = -1;
int handlerFuncIndex = -1;
boolean hasattr = false; boolean hasattr = false;
Attribute[] atts = new Attribute[paramTypes.length + 1]; Attribute[] atts = new Attribute[paramTypes.length + 1];
if (anns.length > 0) { if (anns.length > 0) {
Class<?>[] params = method.getParameterTypes(); Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
if (AsyncHandler.class.isAssignableFrom(params[i])) {
handlerFuncIndex = i;
break;
}
}
for (int i = 0; i < anns.length; i++) { for (int i = 0; i < anns.length; i++) {
if (anns[i].length > 0) { if (anns[i].length > 0) {
for (Annotation ann : anns[i]) { for (Annotation ann : anns[i]) {
if (ann.annotationType() == RpcTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) { if (ann.annotationType() == RpcAttachment.class) {
handlerAttachIndex = i;
} else if (ann.annotationType() == RpcTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
targetAddrIndex = i; targetAddrIndex = i;
} else if (ann.annotationType() == RpcSourceAddress.class && SocketAddress.class.isAssignableFrom(params[i])) { } else if (ann.annotationType() == RpcSourceAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
sourceAddrIndex = i; sourceAddrIndex = i;
@@ -91,7 +103,18 @@ public final class SncpClient {
} }
this.addressTargetParamIndex = targetAddrIndex; this.addressTargetParamIndex = targetAddrIndex;
this.addressSourceParamIndex = sourceAddrIndex; this.addressSourceParamIndex = sourceAddrIndex;
this.handlerFuncParamIndex = handlerFuncIndex;
this.handlerAttachParamIndex = handlerAttachIndex;
this.paramAttrs = hasattr ? atts : null; this.paramAttrs = hasattr ? atts : null;
if (handlerFuncIndex > 0) {
Type handlerFuncType = this.paramTypes[handlerFuncIndex];
if (handlerFuncType instanceof ParameterizedType) {
ParameterizedType handlerpt = (ParameterizedType) handlerFuncType;
//后续可以添加验证, AsyncHandler的第一个泛型必须与方法返回值类型相同 第二个泛型必须与@RpcAttachment的参数类型相同
//需要考虑AsyncHandler的子类形态 有可能0、1、2、。。。多个泛型
}
this.paramTypes[handlerFuncIndex] = AsyncHandler.class;
}
} }
@Override @Override
@@ -222,8 +245,9 @@ public final class SncpClient {
public void remoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) { public void remoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
final SncpAction action = actions[index]; final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (InetSocketAddress addr : transport.getRemoteAddresses()) { for (InetSocketAddress addr : transport.getRemoteAddresses()) {
remote0(bsonConvert, jsonConvert, transport, addr, action, params); remote0(null, bsonConvert, jsonConvert, transport, addr, action, params);
} }
} }
@@ -240,8 +264,9 @@ public final class SncpClient {
public void remoteDiffGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport[] transports, final int index, final Object... params) { public void remoteDiffGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport[] transports, final int index, final Object... params) {
if (transports == null || transports.length < 1) return; if (transports == null || transports.length < 1) return;
final SncpAction action = actions[index]; final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (Transport transport : transports) { for (Transport transport : transports) {
remote0(bsonConvert, jsonConvert, transport, null, action, params); remote0(null, bsonConvert, jsonConvert, transport, null, action, params);
} }
} }
@@ -259,8 +284,10 @@ public final class SncpClient {
//只给远程模式调用的 //只给远程模式调用的
public <T> T remote(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) { public <T> T remote(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
final SncpAction action = actions[index]; final SncpAction action = actions[index];
SncpFuture<byte[]> future = remote0(bsonConvert, jsonConvert, transport, null, action, params); final AsyncHandler handlerFunc = action.handlerFuncParamIndex >= 0 ? (AsyncHandler) params[action.handlerFuncParamIndex] : null;
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null;
SncpFuture<byte[]> future = remote0(handlerFunc, bsonConvert, jsonConvert, transport, null, action, params);
if (handlerFunc != null) return null;
final BsonReader reader = bsonConvert.pollBsonReader(); final BsonReader reader = bsonConvert.pollBsonReader();
try { try {
reader.setBytes(future.get(5, TimeUnit.SECONDS)); reader.setBytes(future.get(5, TimeUnit.SECONDS));
@@ -282,22 +309,23 @@ public final class SncpClient {
if (transports == null || transports.length < 1) return; if (transports == null || transports.length < 1) return;
remote(bsonConvert, jsonConvert, transports[0], index, params); remote(bsonConvert, jsonConvert, transports[0], index, params);
for (int i = 1; i < transports.length; i++) { for (int i = 1; i < transports.length; i++) {
remote0(bsonConvert, jsonConvert, transports[i], null, actions[index], params); remote0(null, bsonConvert, jsonConvert, transports[i], null, actions[index], params);
} }
} }
private SncpFuture<byte[]> remote0(final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { private SncpFuture<byte[]> remote0(final AsyncHandler handler, final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
if ("rest".equalsIgnoreCase(transport.getKind())) { if ("rest".equalsIgnoreCase(transport.getSubprotocol())) {
return remoteRest0(jsonConvert, transport, addr0, action, params); return remoteRest0(handler, jsonConvert, transport, addr0, action, params);
} }
return remoteSncp0(bsonConvert, transport, addr0, action, params); return remoteSncp0(handler, bsonConvert, transport, addr0, action, params);
} }
private SncpFuture<byte[]> remoteRest0(final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { //尚未实现
private SncpFuture<byte[]> remoteRest0(final AsyncHandler handler, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
return null; return null;
} }
private SncpFuture<byte[]> remoteSncp0(final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) { private SncpFuture<byte[]> remoteSncp0(final AsyncHandler handler, final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
Type[] myparamtypes = action.paramTypes; Type[] myparamtypes = action.paramTypes;
if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.clientAddress; if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.clientAddress;
final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入 final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
@@ -400,6 +428,24 @@ public final class SncpClient {
future.set(this.body); future.set(this.body);
transport.offerBuffer(buffer); transport.offerBuffer(buffer);
transport.offerConnection(false, conn); transport.offerConnection(false, conn);
if (handler != null) {
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
final BsonReader reader = bsonConvert.pollBsonReader();
try {
reader.setBytes(this.body);
int i;
while ((i = (reader.readByte() & 0xff)) != 0) {
final Attribute attr = action.paramAttrs[i];
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
}
Object rs = bsonConvert.convertFrom(action.resultTypes, reader);
handler.completed(rs, handlerAttach);
} catch (Exception e) {
handler.failed(e, handlerAttach);
} finally {
bsonConvert.offerBsonReader(reader);
}
}
} }
@Override @Override
@@ -408,6 +454,10 @@ public final class SncpClient {
future.set(new RuntimeException(action.method + " sncp remote exec failed")); future.set(new RuntimeException(action.method + " sncp remote exec failed"));
transport.offerBuffer(buffer); transport.offerBuffer(buffer);
transport.offerConnection(true, conn); transport.offerConnection(true, conn);
if (handler != null) {
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
handler.failed(exc, handlerAttach);
}
} }
}); });
} }

View File

@@ -80,7 +80,7 @@ public final class SncpDynServlet extends SncpServlet {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName()).append("(type=").append(type.getName()); sb.append(this.getClass().getSimpleName()).append(" (type=").append(type.getName());
int len = maxClassNameLength - type.getName().length(); int len = maxClassNameLength - type.getName().length();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
sb.append(' '); sb.append(' ');

View File

@@ -191,6 +191,13 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
return !entry.isExpired(); return !entry.isExpired();
} }
@Override
public boolean exists(final AsyncHandler<Boolean, K> handler, @RpcAttachment final K key) {
boolean rs = exists(key);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
public V get(K key) { public V get(K key) {
if (key == null) return null; if (key == null) return null;
@@ -201,6 +208,13 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
return (V) entry.getValue(); return (V) entry.getValue();
} }
@Override
public V get(final AsyncHandler<V, K> handler, @RpcAttachment final K key) {
V rs = get(key);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public V getAndRefresh(K key, final int expireSeconds) { public V getAndRefresh(K key, final int expireSeconds) {
@@ -214,6 +228,13 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
return (V) entry.getValue(); return (V) entry.getValue();
} }
@Override
public V getAndRefresh(final AsyncHandler<V, K> handler, @RpcAttachment final K key, final int expireSeconds) {
V rs = getAndRefresh(key, expireSeconds);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void refresh(K key, final int expireSeconds) { public void refresh(K key, final int expireSeconds) {
@@ -224,6 +245,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
entry.expireSeconds = expireSeconds; entry.expireSeconds = expireSeconds;
} }
@Override
public void refresh(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final int expireSeconds) {
refresh(key, expireSeconds);
if (handler != null) handler.completed(null, key);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void set(K key, V value) { public void set(K key, V value) {
@@ -239,6 +266,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
} }
} }
@Override
public void set(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
set(key, value);
if (handler != null) handler.completed(null, key);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void set(int expireSeconds, K key, V value) { public void set(int expireSeconds, K key, V value) {
@@ -254,6 +287,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
} }
} }
@Override
public void set(final AsyncHandler<Void, K> handler, final int expireSeconds, @RpcAttachment final K key, final V value) {
set(expireSeconds, key, value);
if (handler != null) handler.completed(null, key);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void setExpireSeconds(K key, int expireSeconds) { public void setExpireSeconds(K key, int expireSeconds) {
@@ -263,6 +302,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
entry.expireSeconds = expireSeconds; entry.expireSeconds = expireSeconds;
} }
@Override
public void setExpireSeconds(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final int expireSeconds) {
setExpireSeconds(key, expireSeconds);
if (handler != null) handler.completed(null, key);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void remove(K key) { public void remove(K key) {
@@ -270,16 +315,36 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
container.remove(key); container.remove(key);
} }
@Override
public void remove(final AsyncHandler<Void, K> handler, @RpcAttachment final K key) {
remove(key);
if (handler != null) handler.completed(null, key);
}
@Override @Override
public Collection<V> getCollection(final K key) { public Collection<V> getCollection(final K key) {
return (Collection<V>) get(key); return (Collection<V>) get(key);
} }
@Override
public Collection<V> getCollection(final AsyncHandler<Collection<V>, K> handler, @RpcAttachment final K key) {
Collection<V> rs = getCollection(key);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
public Collection<V> getCollectionAndRefresh(final K key, final int expireSeconds) { public Collection<V> getCollectionAndRefresh(final K key, final int expireSeconds) {
return (Collection<V>) getAndRefresh(key, expireSeconds); return (Collection<V>) getAndRefresh(key, expireSeconds);
} }
@Override
public Collection<V> getCollectionAndRefresh(final AsyncHandler<Collection<V>, K> handler, @RpcAttachment final K key, final int expireSeconds) {
Collection<V> rs = getCollectionAndRefresh(key, expireSeconds);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void appendListItem(K key, V value) { public void appendListItem(K key, V value) {
@@ -296,6 +361,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
} }
} }
@Override
public void appendListItem(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
appendListItem(key, value);
if (handler != null) handler.completed(null, key);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void removeListItem(K key, V value) { public void removeListItem(K key, V value) {
@@ -305,6 +376,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
((Collection) entry.getValue()).remove(value); ((Collection) entry.getValue()).remove(value);
} }
@Override
public void removeListItem(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
removeListItem(key, value);
if (handler != null) handler.completed(null, key);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void appendSetItem(K key, V value) { public void appendSetItem(K key, V value) {
@@ -321,6 +398,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
} }
} }
@Override
public void appendSetItem(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
appendSetItem(key, value);
if (handler != null) handler.completed(null, key);
}
@Override @Override
@RpcMultiRun @RpcMultiRun
public void removeSetItem(K key, V value) { public void removeSetItem(K key, V value) {
@@ -330,6 +413,12 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
((Set) entry.getValue()).remove(value); ((Set) entry.getValue()).remove(value);
} }
@Override
public void removeSetItem(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
removeSetItem(key, value);
if (handler != null) handler.completed(null, key);
}
public static enum CacheEntryType { public static enum CacheEntryType {
OBJECT, SET, LIST; OBJECT, SET, LIST;
} }

View File

@@ -33,54 +33,178 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
source.insert(values); source.insert(values);
} }
@Override
public <T> void insert(final AsyncHandler<Void, T[]> handler, @RpcAttachment @RpcCall(DataCallArrayAttribute.class) final T... values) {
source.insert(values);
if (handler != null) handler.completed(null, values);
}
@Override @Override
public <T> int delete(T... values) { public <T> int delete(T... values) {
return source.delete(values); return source.delete(values);
} }
@Override
public <T> int delete(final AsyncHandler<Integer, T[]> handler, @RpcAttachment final T... values) {
int rs = source.delete(values);
if (handler != null) handler.completed(rs, values);
return rs;
}
@Override @Override
public <T> int delete(final Class<T> clazz, final Serializable... ids) { public <T> int delete(final Class<T> clazz, final Serializable... ids) {
return source.delete(clazz, ids); return source.delete(clazz, ids);
} }
@Override
public <T> int delete(final AsyncHandler<Integer, Serializable[]> handler, final Class<T> clazz, @RpcAttachment final Serializable... ids) {
int rs = source.delete(clazz, ids);
if (handler != null) handler.completed(rs, ids);
return rs;
}
@Override @Override
public <T> int delete(final Class<T> clazz, FilterNode node) { public <T> int delete(final Class<T> clazz, FilterNode node) {
return source.delete(clazz, node); return source.delete(clazz, node);
} }
@Override
public <T> int delete(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
int rs = source.delete(clazz, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override
public <T> int delete(final Class<T> clazz, final Flipper flipper, FilterNode node) {
return source.delete(clazz, flipper, node);
}
@Override
public <T> int delete(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment FilterNode node) {
int rs = source.delete(clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T> int update(T... values) { public <T> int update(T... values) {
return source.update(values); return source.update(values);
} }
@Override
public <T> int update(final AsyncHandler<Integer, T[]> handler, @RpcAttachment final T... values) {
int rs = source.update(values);
if (handler != null) handler.completed(rs, values);
return rs;
}
@Override @Override
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value) { public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value) {
return source.updateColumn(clazz, id, column, value); return source.updateColumn(clazz, id, column, value);
} }
@Override
public <T> int updateColumn(final AsyncHandler<Integer, Serializable> handler, final Class<T> clazz, @RpcAttachment final Serializable id, final String column, final Serializable value) {
int rs = source.updateColumn(clazz, id, column, value);
if (handler != null) handler.completed(rs, id);
return rs;
}
@Override @Override
public <T> int updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node) { public <T> int updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node) {
return source.updateColumn(clazz, column, value, node); return source.updateColumn(clazz, column, value, node);
} }
@Override
public <T> int updateColumn(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, final String column, final Serializable value, @RpcAttachment final FilterNode node) {
int rs = source.updateColumn(clazz, column, value, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) { public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
return source.updateColumn(clazz, id, values); return source.updateColumn(clazz, id, values);
} }
@Override
public <T> int updateColumn(final AsyncHandler<Integer, Serializable> handler, final Class<T> clazz, @RpcAttachment final Serializable id, final ColumnValue... values) {
int rs = source.updateColumn(clazz, id, values);
if (handler != null) handler.completed(rs, id);
return rs;
}
@Override @Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) { public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
return source.updateColumn(clazz, node, values); return source.updateColumn(clazz, node, values);
} }
@Override @Override
public <T> int updateColumns(T bean, final String... columns) { public <T> int updateColumn(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node, final ColumnValue... values) {
return source.updateColumns(bean, columns); int rs = source.updateColumn(clazz, node, values);
if (handler != null) handler.completed(rs, node);
return rs;
} }
@Override @Override
public <T> int updateColumns(T bean, final FilterNode node, final String... columns) { public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
return source.updateColumns(bean, node, columns); return source.updateColumn(clazz, node, flipper, values);
}
@Override
public <T> int updateColumn(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node, final Flipper flipper, final ColumnValue... values) {
int rs = source.updateColumn(clazz, node, flipper, values);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override
public <T> int updateColumn(T bean, final String... columns) {
return source.updateColumn(bean, columns);
}
@Override
public <T> int updateColumn(final AsyncHandler<Integer, T> handler, @RpcAttachment final T bean, final String... columns) {
int rs = source.updateColumn(bean, columns);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override
public <T> int updateColumn(T bean, final FilterNode node, final String... columns) {
return source.updateColumn(bean, node, columns);
}
@Override
public <T> int updateColumn(final AsyncHandler<Integer, FilterNode> handler, final T bean, @RpcAttachment final FilterNode node, final String... columns) {
int rs = source.updateColumn(bean, node, columns);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override
public <T> int updateColumn(T bean, final SelectColumn selects) {
return source.updateColumn(bean, selects);
}
@Override
public <T> int updateColumn(final AsyncHandler<Integer, T> handler, @RpcAttachment final T bean, final SelectColumn selects) {
int rs = source.updateColumn(bean, selects);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override
public <T> int updateColumn(T bean, final FilterNode node, final SelectColumn selects) {
return source.updateColumn(bean, node, selects);
}
@Override
public <T> int updateColumn(final AsyncHandler<Integer, FilterNode> handler, final T bean, @RpcAttachment final FilterNode node, final SelectColumn selects) {
int rs = source.updateColumn(bean, node, selects);
if (handler != null) handler.completed(rs, node);
return rs;
} }
@Override @Override
@@ -88,206 +212,625 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
return source.getNumberResult(entityClass, func, column); return source.getNumberResult(entityClass, func, column);
} }
@Override
public Number getNumberResult(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, @RpcAttachment final String column) {
Number rs = source.getNumberResult(entityClass, func, column);
if (handler != null) handler.completed(rs, column);
return rs;
}
@Override @Override
public final Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterBean bean) { public final Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean)); return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <B extends FilterBean> Number getNumberResult(final AsyncHandler<Number, B> handler, final Class entityClass, final FilterFunc func, final String column, @RpcAttachment final B bean) {
Number rs = source.getNumberResult(entityClass, func, column, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterNode node) { public Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterNode node) {
return source.getNumberResult(entityClass, func, column, node); return source.getNumberResult(entityClass, func, column, node);
} }
@Override
public Number getNumberResult(final AsyncHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, @RpcAttachment final FilterNode node) {
Number rs = source.getNumberResult(entityClass, func, column, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column) { public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column) {
return source.getNumberResult(entityClass, func, defVal, column); return source.getNumberResult(entityClass, func, defVal, column);
} }
@Override
public Number getNumberResult(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final Number defVal, @RpcAttachment final String column) {
Number rs = source.getNumberResult(entityClass, func, defVal, column);
if (handler != null) handler.completed(rs, column);
return rs;
}
@Override @Override
public final Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterBean bean) { public final Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean));
} }
@Override
public Number getNumberResult(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final Number defVal, @RpcAttachment final String column, final FilterBean bean) {
Number rs = source.getNumberResult(entityClass, func, defVal, column, bean);
if (handler != null) handler.completed(rs, column);
return rs;
}
@Override @Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterNode node) { public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterNode node) {
return source.getNumberResult(entityClass, func, defVal, column, node); return source.getNumberResult(entityClass, func, defVal, column, node);
} }
@Override
public Number getNumberResult(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final Number defVal, @RpcAttachment final String column, final FilterNode node) {
Number rs = source.getNumberResult(entityClass, func, defVal, column, node);
if (handler != null) handler.completed(rs, column);
return rs;
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterFuncColumn... columns) {
return source.getNumberMap(entityClass, columns);
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final AsyncHandler<Map<String, N>, FilterFuncColumn[]> handler, final Class entityClass, @RpcAttachment final FilterFuncColumn... columns) {
Map<String, N> rs = source.getNumberMap(entityClass, columns);
if (handler != null) handler.completed(rs, columns);
return rs;
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) {
return source.getNumberMap(entityClass, bean, columns);
}
@Override
public <N extends Number, B extends FilterBean> Map<String, N> getNumberMap(final AsyncHandler<Map<String, N>, B> handler, final Class entityClass, @RpcAttachment final B bean, final FilterFuncColumn... columns) {
Map<String, N> rs = source.getNumberMap(entityClass, bean, columns);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) {
return source.getNumberMap(entityClass, node, columns);
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final AsyncHandler<Map<String, N>, FilterNode> handler, final Class entityClass, @RpcAttachment final FilterNode node, final FilterFuncColumn... columns) {
Map<String, N> rs = source.getNumberMap(entityClass, node, columns);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn) { public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn) {
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn); return source.queryColumnMap(entityClass, keyColumn, func, funcColumn);
} }
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final AsyncHandler<Map<K, N>, String> handler, final Class<T> entityClass, @RpcAttachment final String keyColumn, final FilterFunc func, final String funcColumn) {
Map<K, N> rs = source.queryColumnMap(entityClass, keyColumn, func, funcColumn);
if (handler != null) handler.completed(rs, keyColumn);
return rs;
}
@Override @Override
public final <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterBean bean) { public final <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterBean bean) {
return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final AsyncHandler<Map<K, N>, String> handler, final Class<T> entityClass, @RpcAttachment final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) {
Map<K, N> rs = source.queryColumnMap(entityClass, keyColumn, func, funcColumn, bean);
if (handler != null) handler.completed(rs, keyColumn);
return rs;
}
@Override @Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterNode node) { public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterNode node) {
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn, node); return source.queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
} }
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final AsyncHandler<Map<K, N>, String> handler, final Class<T> entityClass, @RpcAttachment final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node) {
Map<K, N> rs = source.queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
if (handler != null) handler.completed(rs, keyColumn);
return rs;
}
@Override @Override
public <T> T find(final Class<T> clazz, final Serializable pk) { public <T> T find(final Class<T> clazz, final Serializable pk) {
return source.find(clazz, pk); return source.find(clazz, pk);
} }
@Override
public <T> T find(final AsyncHandler<T, Serializable> handler, final Class<T> clazz, @RpcAttachment final Serializable pk) {
T rs = source.find(clazz, pk);
if (handler != null) handler.completed(rs, pk);
return rs;
}
@Override @Override
public <T> T find(final Class<T> clazz, SelectColumn selects, final Serializable pk) { public <T> T find(final Class<T> clazz, SelectColumn selects, final Serializable pk) {
return source.find(clazz, selects, pk); return source.find(clazz, selects, pk);
} }
@Override
public <T> T find(final AsyncHandler<T, Serializable> handler, final Class<T> clazz, SelectColumn selects, @RpcAttachment final Serializable pk) {
T rs = source.find(clazz, selects, pk);
if (handler != null) handler.completed(rs, pk);
return rs;
}
@Override @Override
public <T> T find(final Class<T> clazz, final String column, final Serializable key) { public <T> T find(final Class<T> clazz, final String column, final Serializable key) {
return source.find(clazz, column, key); return source.find(clazz, column, key);
} }
@Override
public <T> T find(final AsyncHandler<T, Serializable> handler, final Class<T> clazz, final String column, @RpcAttachment final Serializable key) {
T rs = source.find(clazz, column, key);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
public final <T> T find(final Class<T> clazz, FilterBean bean) { public final <T> T find(final Class<T> clazz, FilterBean bean) {
return find(clazz, FilterNodeBean.createFilterNode(bean)); return find(clazz, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> T find(final AsyncHandler<T, B> handler, final Class<T> clazz, @RpcAttachment final B bean) {
T rs = source.find(clazz, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> T find(final Class<T> clazz, FilterNode node) { public <T> T find(final Class<T> clazz, FilterNode node) {
return source.find(clazz, node); return source.find(clazz, node);
} }
@Override
public <T> T find(final AsyncHandler<T, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
T rs = source.find(clazz, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public final <T> T find(final Class<T> clazz, final SelectColumn selects, FilterBean bean) { public final <T> T find(final Class<T> clazz, final SelectColumn selects, FilterBean bean) {
return find(clazz, selects, FilterNodeBean.createFilterNode(bean)); return find(clazz, selects, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> T find(final AsyncHandler<T, B> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final B bean) {
T rs = source.find(clazz, selects, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node) { public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
return source.find(clazz, selects, node); return source.find(clazz, selects, node);
} }
@Override
public <T> T find(final AsyncHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final FilterNode node) {
T rs = source.find(clazz, selects, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable pk) {
return source.findColumn(clazz, column, pk);
}
@Override
public <T> Serializable findColumn(final AsyncHandler<Serializable, Serializable> handler, final Class<T> clazz, final String column, @RpcAttachment final Serializable pk) {
Serializable rs = source.findColumn(clazz, column, pk);
if (handler != null) handler.completed(rs, pk);
return rs;
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterBean bean) {
return source.findColumn(clazz, column, bean);
}
@Override
public <T, B extends FilterBean> Serializable findColumn(final AsyncHandler<Serializable, B> handler, final Class<T> clazz, final String column, @RpcAttachment final B bean) {
Serializable rs = source.findColumn(clazz, column, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterNode node) {
return source.findColumn(clazz, column, node);
}
@Override
public <T> Serializable findColumn(final AsyncHandler<Serializable, FilterNode> handler, final Class<T> clazz, final String column, @RpcAttachment final FilterNode node) {
Serializable rs = source.findColumn(clazz, column, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final Serializable pk) {
return source.findColumn(clazz, column, defValue, pk);
}
@Override
public <T> Serializable findColumn(final AsyncHandler<Serializable, Serializable> handler, final Class<T> clazz, final String column, final Serializable defValue, @RpcAttachment final Serializable pk) {
Serializable rs = source.findColumn(clazz, column, defValue, pk);
if (handler != null) handler.completed(rs, pk);
return rs;
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterBean bean) {
return source.findColumn(clazz, column, defValue, bean);
}
@Override
public <T, B extends FilterBean> Serializable findColumn(final AsyncHandler<Serializable, B> handler, final Class<T> clazz, final String column, final Serializable defValue, @RpcAttachment final B bean) {
Serializable rs = source.findColumn(clazz, column, defValue, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node) {
return source.findColumn(clazz, column, defValue, node);
}
@Override
public <T> Serializable findColumn(final AsyncHandler<Serializable, FilterNode> handler, final Class<T> clazz, final String column, final Serializable defValue, @RpcAttachment final FilterNode node) {
Serializable rs = source.findColumn(clazz, column, defValue, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T> boolean exists(final Class<T> clazz, final Serializable pk) { public <T> boolean exists(final Class<T> clazz, final Serializable pk) {
return source.exists(clazz, pk); return source.exists(clazz, pk);
} }
@Override
public <T> boolean exists(final AsyncHandler<Boolean, Serializable> handler, final Class<T> clazz, @RpcAttachment final Serializable pk) {
boolean rs = source.exists(clazz, pk);
if (handler != null) handler.completed(rs, pk);
return rs;
}
@Override @Override
public final <T> boolean exists(final Class<T> clazz, FilterBean bean) { public final <T> boolean exists(final Class<T> clazz, FilterBean bean) {
return exists(clazz, FilterNodeBean.createFilterNode(bean)); return exists(clazz, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> boolean exists(final AsyncHandler<Boolean, B> handler, final Class<T> clazz, @RpcAttachment final B bean) {
boolean rs = source.exists(clazz, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> boolean exists(final Class<T> clazz, FilterNode node) { public <T> boolean exists(final Class<T> clazz, FilterNode node) {
return source.exists(clazz, node); return source.exists(clazz, node);
} }
@Override
public <T> boolean exists(final AsyncHandler<Boolean, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
boolean rs = source.exists(clazz, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, final String column, final Serializable key) { public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, final String column, final Serializable key) {
return source.queryColumnSet(selectedColumn, clazz, column, key); return source.queryColumnSet(selectedColumn, clazz, column, key);
} }
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(final AsyncHandler<HashSet<V>, String> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final String column, final Serializable key) {
HashSet<V> rs = source.queryColumnSet(selectedColumn, clazz, column, key);
if (handler != null) handler.completed(rs, column);
return rs;
}
@Override @Override
public final <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterBean bean) { public final <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterBean bean) {
return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, V extends Serializable, B extends FilterBean> HashSet<V> queryColumnSet(final AsyncHandler<HashSet<V>, B> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final B bean) {
HashSet<V> rs = source.queryColumnSet(selectedColumn, clazz, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterNode node) { public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterNode node) {
return source.queryColumnSet(selectedColumn, clazz, node); return source.queryColumnSet(selectedColumn, clazz, node);
} }
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(final AsyncHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final FilterNode node) {
HashSet<V> rs = source.queryColumnSet(selectedColumn, clazz, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, final String column, final Serializable key) { public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, final String column, final Serializable key) {
return source.queryColumnList(selectedColumn, clazz, column, key); return source.queryColumnList(selectedColumn, clazz, column, key);
} }
@Override
public <T, V extends Serializable> List<V> queryColumnList(final AsyncHandler<List<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, @RpcAttachment final Serializable key) {
List<V> rs = source.queryColumnList(selectedColumn, clazz, column, key);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterBean bean) { public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterBean bean) {
return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, V extends Serializable, B extends FilterBean> List<V> queryColumnList(final AsyncHandler<List<V>, B> handler, String selectedColumn, Class<T> clazz, @RpcAttachment final B bean) {
List<V> rs = source.queryColumnList(selectedColumn, clazz, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterNode node) { public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterNode node) {
return source.queryColumnList(selectedColumn, clazz, node); return source.queryColumnList(selectedColumn, clazz, node);
} }
@Override
public <T, V extends Serializable> List<V> queryColumnList(final AsyncHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final FilterNode node) {
List<V> rs = source.queryColumnList(selectedColumn, clazz, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override
public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) {
return queryColumnList(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable, B extends FilterBean> List<V> queryColumnList(final AsyncHandler<List<V>, B> handler, String selectedColumn, Class<T> clazz, Flipper flipper, @RpcAttachment final B bean) {
List<V> rs = source.queryColumnList(selectedColumn, clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) {
return source.queryColumnList(selectedColumn, clazz, flipper, node);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final AsyncHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, Flipper flipper, @RpcAttachment final FilterNode node) {
List<V> rs = source.queryColumnList(selectedColumn, clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public final <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) { public final <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) {
return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, V extends Serializable, B extends FilterBean> Sheet<V> queryColumnSheet(final AsyncHandler<Sheet<V>, B> handler, String selectedColumn, Class<T> clazz, Flipper flipper, @RpcAttachment B bean) {
Sheet<V> rs = source.queryColumnSheet(selectedColumn, clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) { public <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) {
return source.queryColumnSheet(selectedColumn, clazz, flipper, node); return source.queryColumnSheet(selectedColumn, clazz, flipper, node);
} }
@Override
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final AsyncHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, @RpcAttachment final FilterNode node) {
Sheet<V> rs = source.queryColumnSheet(selectedColumn, clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key) { public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key) {
return source.queryList(clazz, column, key); return source.queryList(clazz, column, key);
} }
@Override
public <T> List<T> queryList(final AsyncHandler<List<T>, Serializable> handler, final Class<T> clazz, final String column, @RpcAttachment final Serializable key) {
List<T> rs = source.queryList(clazz, column, key);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
public final <T> List<T> queryList(final Class<T> clazz, final FilterBean bean) { public final <T> List<T> queryList(final Class<T> clazz, final FilterBean bean) {
return queryList(clazz, FilterNodeBean.createFilterNode(bean)); return queryList(clazz, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> List<T> queryList(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, @RpcAttachment final B bean) {
List<T> rs = source.queryList(clazz, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> List<T> queryList(final Class<T> clazz, final FilterNode node) { public <T> List<T> queryList(final Class<T> clazz, final FilterNode node) {
return source.queryList(clazz, node); return source.queryList(clazz, node);
} }
@Override
public <T> List<T> queryList(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
List<T> rs = source.queryList(clazz, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) { public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
return queryList(clazz, FilterNodeBean.createFilterNode(bean)); return queryList(clazz, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> List<T> queryList(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final B bean) {
List<T> rs = source.queryList(clazz, selects, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node) { public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
return source.queryList(clazz, selects, node); return source.queryList(clazz, selects, node);
} }
@Override
public <T> List<T> queryList(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final FilterNode node) {
List<T> rs = source.queryList(clazz, selects, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key) { public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key) {
return source.queryList(clazz, flipper, column, key); return source.queryList(clazz, flipper, column, key);
} }
@Override
public <T> List<T> queryList(final AsyncHandler<List<T>, Serializable> handler, final Class<T> clazz, final Flipper flipper, final String column, @RpcAttachment final Serializable key) {
List<T> rs = source.queryList(clazz, flipper, column, key);
if (handler != null) handler.completed(rs, key);
return rs;
}
@Override @Override
public final <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean) { public final <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return queryList(clazz, flipper, FilterNodeBean.createFilterNode(bean)); return queryList(clazz, flipper, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> List<T> queryList(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final B bean) {
List<T> rs = source.queryList(clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node) { public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return source.queryList(clazz, flipper, node); return source.queryList(clazz, flipper, node);
} }
@Override
public <T> List<T> queryList(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final FilterNode node) {
List<T> rs = source.queryList(clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> List<T> queryList(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final B bean) {
List<T> rs = source.queryList(clazz, selects, flipper, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return source.queryList(clazz, selects, flipper, node); return source.queryList(clazz, selects, flipper, node);
} }
@Override
public <T> List<T> queryList(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final FilterNode node) {
List<T> rs = source.queryList(clazz, selects, flipper, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public final <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean) { public final <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return querySheet(clazz, flipper, FilterNodeBean.createFilterNode(bean)); return querySheet(clazz, flipper, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> Sheet<T> querySheet(final AsyncHandler<Sheet<T>, B> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final B bean) {
Sheet<T> rs = source.querySheet(clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node) { public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return source.querySheet(clazz, flipper, node); return source.querySheet(clazz, flipper, node);
} }
@Override
public <T> Sheet<T> querySheet(final AsyncHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final FilterNode node) {
Sheet<T> rs = source.querySheet(clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public final <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { public final <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
} }
@Override
public <T, B extends FilterBean> Sheet<T> querySheet(final AsyncHandler<Sheet<T>, B> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final B bean) {
Sheet<T> rs = source.querySheet(clazz, selects, flipper, bean);
if (handler != null) handler.completed(rs, bean);
return rs;
}
@Override @Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return source.querySheet(clazz, selects, flipper, node); return source.querySheet(clazz, selects, flipper, node);
} }
@Override
public <T> Sheet<T> querySheet(final AsyncHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final FilterNode node) {
Sheet<T> rs = source.querySheet(clazz, selects, flipper, node);
if (handler != null) handler.completed(rs, node);
return rs;
}
@Override @Override
public void close() throws Exception { public void close() throws Exception {
source.getClass().getMethod("close").invoke(source); source.getClass().getMethod("close").invoke(source);

View File

@@ -7,15 +7,16 @@ package org.redkale.service;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.text.MessageFormat;
import java.util.*; import java.util.*;
/** /**
* 用于定义错误码的注解 * 用于定义错误码的注解 <br>
* 结果码定义范围: * 结果码定义范围: <br>
* // 10000001 - 19999999 预留给Redkale的核心包使用 * // 10000001 - 19999999 预留给Redkale的核心包使用 <br>
* // 20000001 - 29999999 预留给Redkale的扩展包使用 * // 20000001 - 29999999 预留给Redkale的扩展包使用 <br>
* // 30000001 - 99999999 预留给Dev开发系统自身使用 * // 30000001 - 99999999 预留给Dev开发系统自身使用 <br>
* * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
@@ -28,6 +29,39 @@ public @interface RetLabel {
String value(); String value();
public static abstract class AbstractRetCode {
protected static final Map<Integer, String> rets = new HashMap();
protected static void load(Class clazz) {
rets.putAll(RetLoader.load(clazz));
}
public static RetResult retResult(int retcode) {
if (retcode == 0) return RetResult.success();
return new RetResult(retcode, retInfo(retcode));
}
public static RetResult retResult(int retcode, Object... args) {
if (retcode == 0) return RetResult.success();
if (args == null || args.length < 1) return new RetResult(retcode, retInfo(retcode));
String info = MessageFormat.format(retInfo(retcode), args);
return new RetResult(retcode, info);
}
public static RetResult set(RetResult result, int retcode, Object... args) {
if (retcode == 0) return result.retcode(0).retinfo("");
if (args == null || args.length < 1) return result.retcode(retcode).retinfo(retInfo(retcode));
String info = MessageFormat.format(retInfo(retcode), args);
return result.retcode(retcode).retinfo(info);
}
public static String retInfo(int retcode) {
if (retcode == 0) return "成功";
return rets.getOrDefault(retcode, "未知错误");
}
}
public static abstract class RetLoader { public static abstract class RetLoader {
public static Map<Integer, String> load(Class clazz) { public static Map<Integer, String> load(Class clazz) {

View File

@@ -8,13 +8,13 @@ package org.redkale.service;
import org.redkale.convert.json.*; import org.redkale.convert.json.*;
/** /**
* 通用的结果对象在常见的HTTP+JSON接口中返回的结果需要含结果码错误信息和实体对象。 * 通用的结果对象在常见的HTTP+JSON接口中返回的结果需要含结果码错误信息和实体对象。 <br>
* 通常前四位为模块,后四位为操作。 * 结果码定义通常前四位为模块,后四位为操作。<br>
* 结果码定义范围: * 结果码定义范围: <br>
* // 10000001 - 19999999 预留给Redkale的核心包使用 * // 10000001 - 19999999 预留给Redkale的核心包使用 <br>
* // 20000001 - 29999999 预留给Redkale的扩展包使用 * // 20000001 - 29999999 预留给Redkale的扩展包使用 <br>
* // 30000001 - 99999999 预留给Dev开发系统自身使用 * // 30000001 - 99999999 预留给Dev开发系统自身使用 <br>
* * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
@@ -22,13 +22,6 @@ import org.redkale.convert.json.*;
*/ */
public class RetResult<T> { public class RetResult<T> {
/**
* 使用 RetResult.success() 方法代替
*
* @deprecated
*/
private static final RetResult SUCCESS = new RetResult();
protected int retcode; protected int retcode;
protected String retinfo; protected String retinfo;
@@ -119,10 +112,20 @@ public class RetResult<T> {
this.retcode = retcode; this.retcode = retcode;
} }
/**
* 结果信息通常retcode != 0时值为错误信息
*
* @return 结果信息
*/
public String getRetinfo() { public String getRetinfo() {
return retinfo; return retinfo;
} }
/**
* 设置结果信息
*
* @param retinfo 结果信息
*/
public void setRetinfo(String retinfo) { public void setRetinfo(String retinfo) {
this.retinfo = retinfo; this.retinfo = retinfo;
} }
@@ -136,6 +139,11 @@ public class RetResult<T> {
return result; return result;
} }
/**
* 设置结果对象
*
* @param result T
*/
public void setResult(T result) { public void setResult(T result) {
this.result = result; this.result = result;
} }

View File

@@ -3,29 +3,24 @@
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
package org.redkale.source; package org.redkale.service;
import java.lang.annotation.*; import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/** /**
* SNCP协议中用于CompletionHandler回调函数中的attach字段
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@Target({FIELD}) @Inherited
@Documented
@Target({PARAMETER})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface DistributeGenerator { public @interface RpcAttachment {
long initialValue() default 1;
/**
* 如果allocationSize的值小于或等于1,则主键不会加上nodeid
*
* @return allocationSize
*/
int allocationSize() default 1000;
} }

View File

@@ -7,6 +7,7 @@ package org.redkale.source;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import org.redkale.util.*;
/** /**
* *
@@ -51,4 +52,37 @@ public interface CacheSource<K extends Serializable, V extends Object> {
public void removeSetItem(final K key, final V value); public void removeSetItem(final K key, final V value);
//----------------------异步版---------------------------------
public boolean exists(final AsyncHandler<Boolean, K> handler, final K key);
public V get(final AsyncHandler<V, K> handler, final K key);
public V getAndRefresh(final AsyncHandler<V, K> handler, final K key, final int expireSeconds);
public void refresh(final AsyncHandler<Void, K> handler, final K key, final int expireSeconds);
public void set(final AsyncHandler<Void, K> handler, final K key, final V value);
public void set(final AsyncHandler<Void, K> handler, final int expireSeconds, final K key, final V value);
public void setExpireSeconds(final AsyncHandler<Void, K> handler, final K key, final int expireSeconds);
public void remove(final AsyncHandler<Void, K> handler, final K key);
public Collection<V> getCollection(final AsyncHandler<Collection<V>, K> handler, final K key);
public Collection<V> getCollectionAndRefresh(final AsyncHandler<Collection<V>, K> handler, final K key, final int expireSeconds);
public void appendListItem(final AsyncHandler<Void, K> handler, final K key, final V value);
public void removeListItem(final AsyncHandler<Void, K> handler, final K key, final V value);
public void appendSetItem(final AsyncHandler<Void, K> handler, final K key, final V value);
public void removeSetItem(final AsyncHandler<Void, K> handler, final K key, final V value);
default boolean isOpen(final AsyncHandler<Boolean, Void> handler) {
if (handler != null) handler.completed(Boolean.TRUE, null);
return true;
}
} }

View File

@@ -14,9 +14,24 @@ package org.redkale.source;
* @author zhangjx * @author zhangjx
*/ */
public enum ColumnExpress { public enum ColumnExpress {
MOV, //直接赋值 col = val /**
INC, //追加值 col = col + val * 直接赋值 col = val
MUL, //乘值 col = col * val */
MOV,
/**
* 追加值 col = col + val
*/
INC,
/**
* 乘值 col = col * val
*/
MUL,
/**
* 与值 col = col &#38; val
*/
AND, //与值 col = col & val AND, //与值 col = col & val
ORR; //或值 col = col | val /**
* 或值 col = col | val
*/
ORR;
} }

View File

@@ -10,6 +10,7 @@ import static org.redkale.source.ColumnExpress.*;
/** /**
* ColumnValue主要用于多个字段更新的表达式。 * ColumnValue主要用于多个字段更新的表达式。
* 用于 DataSource.updateColumn 方法
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -37,26 +38,74 @@ public class ColumnValue {
this.value = value; this.value = value;
} }
/**
* 同 mov 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue create(String column, Serializable value) { public static ColumnValue create(String column, Serializable value) {
return new ColumnValue(column, value); return new ColumnValue(column, value);
} }
/**
* 返回 {column} = {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue mov(String column, Serializable value) { public static ColumnValue mov(String column, Serializable value) {
return new ColumnValue(column, MOV, value); return new ColumnValue(column, MOV, value);
} }
/**
* 返回 {column} = {column} + {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue inc(String column, Serializable value) { public static ColumnValue inc(String column, Serializable value) {
return new ColumnValue(column, INC, value); return new ColumnValue(column, INC, value);
} }
/**
* 返回 {column} = {column} * {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue mul(String column, Serializable value) { public static ColumnValue mul(String column, Serializable value) {
return new ColumnValue(column, MUL, value); return new ColumnValue(column, MUL, value);
} }
/**
* 返回 {column} = {column} &#38; {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue and(String column, Serializable value) { public static ColumnValue and(String column, Serializable value) {
return new ColumnValue(column, AND, value); return new ColumnValue(column, AND, value);
} }
/**
* 返回 {column} = {column} | {value} 操作
*
* @param column 字段名
* @param value 字段值
*
* @return ColumnValue
*/
public static ColumnValue orr(String column, Serializable value) { public static ColumnValue orr(String column, Serializable value) {
return new ColumnValue(column, ORR, value); return new ColumnValue(column, ORR, value);
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,8 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* Entity分库分表的注解需要结合DistributeTableStrategy使用 <br>
* 标记为 &#64;DistributeTable的Entity类视为需要进行分库分表操作 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -8,6 +8,9 @@ package org.redkale.source;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 分表分库策略,结合&#64;DistributeTable使用 <br>
* 不能与&#64;Cacheable同时使用 <br>
* 使用分表分库功能重点是主键的生成策略,不同场景生成策略不一样 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -17,13 +20,38 @@ import java.io.Serializable;
*/ */
public interface DistributeTableStrategy<T> { public interface DistributeTableStrategy<T> {
default String getTable(String table, Serializable primary) { /**
return null; * 获取对象的表名 <br>
} * 查询单个对象DataSource.find时调用本方法获取表名 <br>
*
default String getTable(String table, FilterNode node) { * @param table 模板表的表名
return null; * @param primary 记录主键
} *
* @return 带库名的全表名
*/
public String getTable(String table, Serializable primary);
/**
* 获取对象的表名 <br>
* 新增对象或更新单个对象DataSource.insert、DataSource.update时调用本方法获取表名 <br>
*
* @param table 模板表的表名
* @param bean 实体对象
*
* @return 带库名的全表名
*/
public String getTable(String table, T bean); public String getTable(String table, T bean);
/**
* 获取对象的表名 <br>
* 查询、修改、删除对象DataSource.find、DataSource.query、DataSource.delete、DataSource.update时调用本方法获取表名 <br>
* 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中 <br>
*
* @param table 模板表的表名
* @param node 过滤条件
*
* @return 带库名的全表名
*/
public String getTable(String table, FilterNode node);
} }

View File

@@ -17,6 +17,7 @@ import static org.redkale.source.FilterFunc.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* Entity数据的缓存类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -27,33 +28,51 @@ import org.redkale.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class EntityCache<T> { public final class EntityCache<T> {
//日志
private static final Logger logger = Logger.getLogger(EntityCache.class.getName()); private static final Logger logger = Logger.getLogger(EntityCache.class.getName());
private final ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap(); //主键与对象的键值对
private ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap();
// CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢10w数据查询需要 0.062秒, 查询慢40%; // CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢10w数据查询需要 0.062秒, 查询慢40%;
private final Collection<T> list = new ConcurrentLinkedQueue(); private Collection<T> list = new ConcurrentLinkedQueue();
//Flipper.sort转换成Comparator的缓存
private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>(); private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>();
//Entity类
private final Class<T> type; private final Class<T> type;
//接口返回的对象是否需要复制一份
private final boolean needcopy; private final boolean needcopy;
//Entity构建器
private final Creator<T> creator; private final Creator<T> creator;
//主键字段
private final Attribute<T, Serializable> primary; private final Attribute<T, Serializable> primary;
//新增时的复制器, 排除了标记为&#064;Transient的字段
private final Reproduce<T, T> newReproduce; private final Reproduce<T, T> newReproduce;
//修改时的复制器, 排除了标记为&#064;Transient或&#064;Column(updatable=false)的字段
private final Reproduce<T, T> chgReproduce; private final Reproduce<T, T> chgReproduce;
//是否已经全量加载过
private volatile boolean fullloaded; private volatile boolean fullloaded;
//Entity信息
final EntityInfo<T> info; final EntityInfo<T> info;
public EntityCache(final EntityInfo<T> info) { //&#064;Cacheable的定时更新秒数为0表示不定时更新
final int interval;
//&#064;Cacheable的定时器
private ScheduledThreadPoolExecutor scheduler;
public EntityCache(final EntityInfo<T> info, final Cacheable c) {
this.info = info; this.info = info;
this.interval = c == null ? 0 : c.interval();
this.type = info.getType(); this.type = info.getType();
this.creator = info.getCreator(); this.creator = info.getCreator();
this.primary = info.primary; this.primary = info.primary;
@@ -80,15 +99,35 @@ public final class EntityCache<T> {
public void fullLoad() { public void fullLoad() {
if (info.fullloader == null) return; if (info.fullloader == null) return;
clear(); this.fullloaded = false;
ConcurrentHashMap newmap = new ConcurrentHashMap();
List<T> all = info.fullloader.apply(info.source, type); List<T> all = info.fullloader.apply(info.source, type);
if (all != null) { if (all != null) {
all.stream().filter(x -> x != null).forEach(x -> { all.stream().filter(x -> x != null).forEach(x -> {
this.map.put(this.primary.get(x), x); newmap.put(this.primary.get(x), x);
}); });
this.list.addAll(all);
} }
this.list = all == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all);
this.map = newmap;
this.fullloaded = true; this.fullloaded = true;
if (this.interval > 0) {
this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
final Thread t = new Thread(r, "EntityCache-" + type + "-Thread");
t.setDaemon(true);
return t;
});
this.scheduler.scheduleAtFixedRate(() -> {
ConcurrentHashMap newmap2 = new ConcurrentHashMap();
List<T> all2 = info.fullloader.apply(info.source, type);
if (all2 != null) {
all2.stream().filter(x -> x != null).forEach(x -> {
newmap2.put(this.primary.get(x), x);
});
}
this.list = all2 == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all2);
this.map = newmap2;
}, interval - System.currentTimeMillis() / 1000 % interval, interval, TimeUnit.SECONDS);
}
} }
public Class<T> getType() { public Class<T> getType() {
@@ -97,8 +136,12 @@ public final class EntityCache<T> {
public void clear() { public void clear() {
this.fullloaded = false; this.fullloaded = false;
this.list.clear(); this.list = new ConcurrentLinkedQueue();
this.map.clear(); this.map = new ConcurrentHashMap();
if (this.scheduler != null) {
this.scheduler.shutdownNow();
this.scheduler = null;
}
} }
public boolean isFullLoaded() { public boolean isFullLoaded() {
@@ -138,6 +181,35 @@ public final class EntityCache<T> {
return t; return t;
} }
public Serializable findColumn(final String column, final Serializable defValue, final Serializable id) {
if (id == null) return defValue;
T rs = map.get(id);
if (rs == null) return defValue;
for (Attribute attr : this.info.attributes) {
if (column.equals(attr.field())) {
Serializable val = (Serializable) attr.get(rs);
return val == null ? defValue : val;
}
}
return defValue;
}
public Serializable findColumn(final String column, final Serializable defValue, FilterNode node) {
final Predicate<T> filter = node == null ? null : node.createPredicate(this);
Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter);
Optional<T> opt = stream.findFirst();
if (!opt.isPresent()) return defValue;
T rs = opt.get();
for (Attribute attr : this.info.attributes) {
if (column.equals(attr.field())) {
Serializable val = (Serializable) attr.get(rs);
return val == null ? defValue : val;
}
}
return defValue;
}
public boolean exists(Serializable id) { public boolean exists(Serializable id) {
if (id == null) return false; if (id == null) return false;
final Class atype = this.primary.type(); final Class atype = this.primary.type();
@@ -321,7 +393,8 @@ public final class EntityCache<T> {
Stream<T> stream = this.list.stream(); Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter); if (filter != null) stream = stream.filter(filter);
if (comparator != null) stream = stream.sorted(comparator); if (comparator != null) stream = stream.sorted(comparator);
if (flipper != null) stream = stream.skip(flipper.getOffset()).limit(flipper.getLimit()); if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset());
if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit());
final List<T> rs = new ArrayList<>(); final List<T> rs = new ArrayList<>();
if (selects == null) { if (selects == null) {
Consumer<? super T> action = x -> rs.add(needcopy ? newReproduce.apply(creator.create(), x) : x); Consumer<? super T> action = x -> rs.add(needcopy ? newReproduce.apply(creator.create(), x) : x);
@@ -371,9 +444,14 @@ public final class EntityCache<T> {
return 1; return 1;
} }
public Serializable[] delete(final FilterNode node) { public Serializable[] delete(final Flipper flipper, final FilterNode node) {
if (node == null || this.list.isEmpty()) return new Serializable[0]; if (node == null || this.list.isEmpty()) return new Serializable[0];
Object[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(); final Comparator<T> comparator = createComparator(flipper);
Stream<T> stream = this.list.stream().filter(node.createPredicate(this));
if (comparator != null) stream = stream.sorted(comparator);
if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset());
if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit());
Object[] rms = stream.toArray();
Serializable[] ids = new Serializable[rms.length]; Serializable[] ids = new Serializable[rms.length];
int i = -1; int i = -1;
for (Object o : rms) { for (Object o : rms) {
@@ -449,9 +527,13 @@ public final class EntityCache<T> {
return rs; return rs;
} }
public <V> T[] updateColumn(final FilterNode node, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) { public <V> T[] updateColumn(final FilterNode node, final Flipper flipper, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0); if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0);
T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); Stream<T> stream = this.list.stream();
final Comparator<T> comparator = createComparator(flipper);
if (comparator != null) stream = stream.sorted(comparator);
if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit());
T[] rms = stream.filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len));
for (T rs : rms) { for (T rs : rms) {
synchronized (rs) { synchronized (rs) {
for (int i = 0; i < attrs.size(); i++) { for (int i = 0; i < attrs.size(); i++) {

View File

@@ -11,14 +11,13 @@ import java.lang.reflect.*;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.*; import java.util.function.*;
import java.util.logging.Level; import java.util.logging.Level;
import javax.persistence.*; import javax.persistence.*;
import static org.redkale.source.DataDefaultSource.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* Entity操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -29,94 +28,116 @@ import org.redkale.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class EntityInfo<T> { public final class EntityInfo<T> {
//全局静态资源
private static final ConcurrentHashMap<Class, EntityInfo> entityInfos = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Class, EntityInfo> entityInfos = new ConcurrentHashMap<>();
//日志
private static final Logger logger = Logger.getLogger(EntityInfo.class); private static final Logger logger = Logger.getLogger(EntityInfo.class);
//Entity类的类 //Entity类名
private final Class<T> type; private final Class<T> type;
//类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null //类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null
final String table; final String table;
//Entity构建器
private final Creator<T> creator; private final Creator<T> creator;
//主键 //主键
final Attribute<T, Serializable> primary; final Attribute<T, Serializable> primary;
//Entity缓存对象
private final EntityCache<T> cache; private final EntityCache<T> cache;
//key是field的name 不是sql字段。 //key是field的name 不是sql字段。
//存放所有与数据库对应的字段, 包括主键 //存放所有与数据库对应的字段, 包括主键
private final HashMap<String, Attribute<T, Serializable>> attributeMap = new HashMap<>(); private final HashMap<String, Attribute<T, Serializable>> attributeMap = new HashMap<>();
//存放所有与数据库对应的字段, 包括主键
final Attribute<T, Serializable>[] attributes; final Attribute<T, Serializable>[] attributes;
//key是field的name value是Column的别名即数据库表的字段名 //key是field的name value是Column的别名即数据库表的字段名
//只有field.name 与 Column.name不同才存放在aliasmap里. //只有field.name 与 Column.name不同才存放在aliasmap里.
private final Map<String, String> aliasmap; private final Map<String, String> aliasmap;
//所有可更新字段,即排除了主键字段和标记为&#064;Column(updatable=false)的字段
private final Map<String, Attribute<T, Serializable>> updateAttributeMap = new HashMap<>(); private final Map<String, Attribute<T, Serializable>> updateAttributeMap = new HashMap<>();
final String containSQL; //用于反向LIKE使用 //用于反向LIKE使用
final String containSQL;
final String notcontainSQL; //用于反向LIKE使用 //用于反向LIKE使用
final String notcontainSQL;
final String tablenotexistSqlstates; //用于判断表不存在的使用, 多个SQLState用;隔开 //用于判断表不存在的使用, 多个SQLState用;隔开
final String tablenotexistSqlstates;
final String tablecopySQL; //用于复制表结构使用 //用于复制表结构使用
final String tablecopySQL;
final Set<String> tables = new HashSet<>(); //用于存在table_20160202类似这种分布式表 //用于存在table_20160202类似这种分布式表
final Set<String> tables = new HashSet<>();
//分表 策略
final DistributeTableStrategy<T> tableStrategy; final DistributeTableStrategy<T> tableStrategy;
//根据主键查找单个对象的SQL
final String querySQL; final String querySQL;
private final Attribute<T, Serializable>[] queryAttributes; //数据库中所有字段 //数据库中所有字段
private final Attribute<T, Serializable>[] queryAttributes;
//新增SQL 含 ?,即排除了自增长主键和标记为&#064;Column(insertable=false)的字段
private final String insertSQL; private final String insertSQL;
final Attribute<T, Serializable>[] insertAttributes; //数据库中所有可新增字段 //数据库中所有可新增字段
final Attribute<T, Serializable>[] insertAttributes;
//根据主键更新所有可更新字段的SQL
private final String updateSQL; private final String updateSQL;
final Attribute<T, Serializable>[] updateAttributes; //数据库中所有可更新字段 //数据库中所有可更新字段
final Attribute<T, Serializable>[] updateAttributes;
//根据主键删除记录的SQL
private final String deleteSQL; private final String deleteSQL;
//日志级别从LogLevel获取
private final int logLevel; private final int logLevel;
//Flipper.sort转换成以ORDER BY开头SQL的缓存
private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>(); private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>();
//---------------------计算主键值---------------------------- //是否由数据库生成主键值
private final int nodeid;
final boolean autoGenerated; final boolean autoGenerated;
//是否UUID主键
final boolean autouuid; final boolean autouuid;
final boolean distributed; //所属的DataSource
boolean initedPrimaryValue = false;
final AtomicLong primaryValue = new AtomicLong(0);
final int allocationSize;
final DataSource source; final DataSource source;
//全量数据的加载器
final BiFunction<DataSource, Class, List> fullloader; final BiFunction<DataSource, Class, List> fullloader;
//------------------------------------------------------------ //------------------------------------------------------------
public static <T> EntityInfo<T> load(Class<T> clazz, final int nodeid, final boolean cacheForbidden, final Properties conf, /**
* 加载EntityInfo
*
* @param type Entity类
* @param cacheForbidden 是否禁用EntityCache
* @param conf 配置信息, persistence.xml中的property节点值
* @param source DataSource,可为null
* @param fullloader 全量加载器,可为null
*/
static <T> EntityInfo<T> load(Class<T> clazz, final boolean cacheForbidden, final Properties conf,
DataSource source, BiFunction<DataSource, Class, List> fullloader) { DataSource source, BiFunction<DataSource, Class, List> fullloader) {
EntityInfo rs = entityInfos.get(clazz); EntityInfo rs = entityInfos.get(clazz);
if (rs != null) return rs; if (rs != null) return rs;
synchronized (entityInfos) { synchronized (entityInfos) {
rs = entityInfos.get(clazz); rs = entityInfos.get(clazz);
if (rs == null) { if (rs == null) {
if (nodeid < 0) throw new IllegalArgumentException("nodeid(" + nodeid + ") is illegal"); rs = new EntityInfo(clazz, cacheForbidden, conf, source, fullloader);
rs = new EntityInfo(clazz, nodeid, cacheForbidden, conf, source, fullloader);
entityInfos.put(clazz, rs); entityInfos.put(clazz, rs);
if (rs.cache != null) { if (rs.cache != null) {
if (fullloader == null) throw new IllegalArgumentException(clazz.getName() + " auto loader is illegal"); if (fullloader == null) throw new IllegalArgumentException(clazz.getName() + " auto loader is illegal");
@@ -127,16 +148,32 @@ public final class EntityInfo<T> {
} }
} }
public static <T> EntityInfo<T> get(Class<T> clazz) { /**
* 获取Entity类对应的EntityInfo对象
*
* @param <T> 泛型
* @param clazz Entity类
*
* @return EntityInfo
*/
static <T> EntityInfo<T> get(Class<T> clazz) {
return entityInfos.get(clazz); return entityInfos.get(clazz);
} }
private EntityInfo(Class<T> type, int nodeid, final boolean cacheForbidden, /**
* 构造函数
*
* @param type Entity类
* @param cacheForbidden 是否禁用EntityCache
* @param conf 配置信息, persistence.xml中的property节点值
* @param source DataSource,可为null
* @param fullloader 全量加载器,可为null
*/
private EntityInfo(Class<T> type, final boolean cacheForbidden,
Properties conf, DataSource source, BiFunction<DataSource, Class, List> fullloader) { Properties conf, DataSource source, BiFunction<DataSource, Class, List> fullloader) {
this.type = type; this.type = type;
this.source = source; this.source = source;
//--------------------------------------------- //---------------------------------------------
this.nodeid = nodeid >= 0 ? nodeid : 0;
LogLevel ll = type.getAnnotation(LogLevel.class); LogLevel ll = type.getAnnotation(LogLevel.class);
this.logLevel = ll == null ? Integer.MIN_VALUE : Level.parse(ll.value()).intValue(); this.logLevel = ll == null ? Integer.MIN_VALUE : Level.parse(ll.value()).intValue();
@@ -153,7 +190,7 @@ public final class EntityInfo<T> {
this.fullloader = loader; this.fullloader = loader;
} else { } else {
this.fullloader = fullloader; this.fullloader = fullloader;
this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? t.name() : (t.catalog() + '.' + t.name()); this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? t.name() : (t.catalog() + '.' + (t.name().isEmpty() ? type.getSimpleName().toLowerCase() : t.name()));
} }
DistributeTable dt = type.getAnnotation(DistributeTable.class); DistributeTable dt = type.getAnnotation(DistributeTable.class);
DistributeTableStrategy dts = null; DistributeTableStrategy dts = null;
@@ -176,8 +213,6 @@ public final class EntityInfo<T> {
List<Attribute<T, Serializable>> updateattrs = new ArrayList<>(); List<Attribute<T, Serializable>> updateattrs = new ArrayList<>();
boolean auto = false; boolean auto = false;
boolean uuid = false; boolean uuid = false;
boolean sqldistribute = false;
int allocationSize0 = 0;
do { do {
for (Field field : cltmp.getDeclaredFields()) { for (Field field : cltmp.getDeclaredFields()) {
@@ -205,17 +240,6 @@ public final class EntityInfo<T> {
// if (gv != null && gv.strategy() != GenerationType.IDENTITY) { // if (gv != null && gv.strategy() != GenerationType.IDENTITY) {
// throw new RuntimeException(cltmp.getName() + "'s @ID primary not a GenerationType.IDENTITY"); // throw new RuntimeException(cltmp.getName() + "'s @ID primary not a GenerationType.IDENTITY");
// } // }
DistributeGenerator dg = field.getAnnotation(DistributeGenerator.class);
if (dg != null) {
if (!field.getType().isPrimitive()) {
throw new RuntimeException(cltmp.getName() + "'s @"
+ DistributeGenerator.class.getSimpleName() + " primary must be primitive class type field");
}
sqldistribute = true;
auto = false;
allocationSize0 = dg.allocationSize();
primaryValue.set(dg.initialValue());
}
if (gv != null && field.getType() == String.class) { //UUID if (gv != null && field.getType() == String.class) { //UUID
uuid = true; uuid = true;
auto = false; auto = false;
@@ -272,118 +296,211 @@ public final class EntityInfo<T> {
} }
this.autoGenerated = auto; this.autoGenerated = auto;
this.autouuid = uuid; this.autouuid = uuid;
this.distributed = sqldistribute;
this.allocationSize = allocationSize0;
//----------------cache-------------- //----------------cache--------------
Cacheable c = type.getAnnotation(Cacheable.class); Cacheable c = type.getAnnotation(Cacheable.class);
if (this.table == null || (!cacheForbidden && c != null && c.value())) { if (this.table == null || (!cacheForbidden && c != null && c.value())) {
this.cache = new EntityCache<>(this); this.cache = new EntityCache<>(this, c);
} else { } else {
this.cache = null; this.cache = null;
} }
if (conf == null) conf = new Properties(); if (conf == null) conf = new Properties();
this.containSQL = conf.getProperty(JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0"); this.containSQL = conf.getProperty(JDBCPoolSource.JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0");
this.notcontainSQL = conf.getProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0"); this.notcontainSQL = conf.getProperty(JDBCPoolSource.JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0");
this.tablenotexistSqlstates = ";" + conf.getProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";"; this.tablenotexistSqlstates = ";" + conf.getProperty(JDBCPoolSource.JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";";
this.tablecopySQL = conf.getProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}"); this.tablecopySQL = conf.getProperty(JDBCPoolSource.JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}");
} }
/**
* 创建主键值目前只支持UUID赋值
*
* @param src Entity对象
*/
public void createPrimaryValue(T src) { public void createPrimaryValue(T src) {
if (autouuid) { if (autouuid) getPrimary().set(src, Utility.uuid());
getPrimary().set(src, Utility.uuid());
return;
}
long v = allocationSize > 1 ? (primaryValue.incrementAndGet() * allocationSize + nodeid) : primaryValue.incrementAndGet();
if (primary.type() == int.class || primary.type() == Integer.class) {
getPrimary().set(src, (Integer) ((Long) v).intValue());
} else {
getPrimary().set(src, v);
}
} }
/**
* 获取Entity缓存器
*
* @return EntityCache
*/
public EntityCache<T> getCache() { public EntityCache<T> getCache() {
return cache; return cache;
} }
/**
* 判断缓存器是否已经全量加载过
*
* @return boolean
*/
public boolean isCacheFullLoaded() { public boolean isCacheFullLoaded() {
return cache != null && cache.isFullLoaded(); return cache != null && cache.isFullLoaded();
} }
/**
* 获取Entity构建器
*
* @return Creator
*/
public Creator<T> getCreator() { public Creator<T> getCreator() {
return creator; return creator;
} }
/**
* 获取Entity类名
*
* @return Class
*/
public Class<T> getType() { public Class<T> getType() {
return type; return type;
} }
/** /**
* 是否虚拟类 * 判断Entity是否虚拟类
* *
* @return 是否虚拟类 * @return boolean
*/ */
public boolean isVirtualEntity() { public boolean isVirtualEntity() {
return table == null; return table == null;
} }
/**
* 获取Entity的INSERT SQL
*
* @param bean Entity对象
*
* @return String
*/
public String getInsertSQL(T bean) { public String getInsertSQL(T bean) {
if (this.tableStrategy == null) return insertSQL; if (this.tableStrategy == null) return insertSQL;
return insertSQL.replace("${newtable}", getTable(bean)); return insertSQL.replace("${newtable}", getTable(bean));
} }
/**
* 获取Entity的UPDATE SQL
*
* @param bean Entity对象
*
* @return String
*/
public String getUpdateSQL(T bean) { public String getUpdateSQL(T bean) {
if (this.tableStrategy == null) return updateSQL; if (this.tableStrategy == null) return updateSQL;
return updateSQL.replace("${newtable}", getTable(bean)); return updateSQL.replace("${newtable}", getTable(bean));
} }
/**
* 获取Entity的DELETE SQL
*
* @param bean Entity对象
*
* @return String
*/
public String getDeleteSQL(T bean) { public String getDeleteSQL(T bean) {
if (this.tableStrategy == null) return deleteSQL; if (this.tableStrategy == null) return deleteSQL;
return deleteSQL.replace("${newtable}", getTable(bean)); return deleteSQL.replace("${newtable}", getTable(bean));
} }
/**
* 根据主键值获取Entity的表名
*
* @param primary Entity主键值
*
* @return String
*/
public String getTable(Serializable primary) { public String getTable(Serializable primary) {
if (tableStrategy == null) return table; if (tableStrategy == null) return table;
String t = tableStrategy.getTable(table, primary); String t = tableStrategy.getTable(table, primary);
return t == null || t.isEmpty() ? table : t; return t == null || t.isEmpty() ? table : t;
} }
/**
* 根据过滤条件获取Entity的表名
*
* @param node 过滤条件
*
* @return String
*/
public String getTable(FilterNode node) { public String getTable(FilterNode node) {
if (tableStrategy == null) return table; if (tableStrategy == null) return table;
String t = tableStrategy.getTable(table, node); String t = tableStrategy.getTable(table, node);
return t == null || t.isEmpty() ? table : t; return t == null || t.isEmpty() ? table : t;
} }
/**
* 根据Entity对象获取Entity的表名
*
* @param bean Entity对象
*
* @return String
*/
public String getTable(T bean) { public String getTable(T bean) {
if (tableStrategy == null) return table; if (tableStrategy == null) return table;
String t = tableStrategy.getTable(table, bean); String t = tableStrategy.getTable(table, bean);
return t == null || t.isEmpty() ? table : t; return t == null || t.isEmpty() ? table : t;
} }
/**
* 获取主键字段的Attribute
*
* @return Attribute
*/
public Attribute<T, Serializable> getPrimary() { public Attribute<T, Serializable> getPrimary() {
return this.primary; return this.primary;
} }
/**
* 遍历数据库表对应的所有字段, 不包含&#64;Transient字段
*
* @param action BiConsumer
*/
public void forEachAttribute(BiConsumer<String, Attribute<T, Serializable>> action) { public void forEachAttribute(BiConsumer<String, Attribute<T, Serializable>> action) {
this.attributeMap.forEach(action); this.attributeMap.forEach(action);
} }
/**
* 根据Entity字段名获取字段的Attribute
*
* @param fieldname Class字段名
*
* @return Attribute
*/
public Attribute<T, Serializable> getAttribute(String fieldname) { public Attribute<T, Serializable> getAttribute(String fieldname) {
if (fieldname == null) return null; if (fieldname == null) return null;
return this.attributeMap.get(fieldname); return this.attributeMap.get(fieldname);
} }
/**
* 根据Entity字段名获取可更新字段的Attribute
*
* @param fieldname Class字段名
*
* @return Attribute
*/
public Attribute<T, Serializable> getUpdateAttribute(String fieldname) { public Attribute<T, Serializable> getUpdateAttribute(String fieldname) {
return this.updateAttributeMap.get(fieldname); return this.updateAttributeMap.get(fieldname);
} }
/**
* 判断Entity类的字段名与表字段名s是否存在不一致的值
*
* @return boolean
*/
public boolean isNoAlias() { public boolean isNoAlias() {
return this.aliasmap == null; return this.aliasmap == null;
} }
/**
* 根据Flipper获取ORDER BY的SQL语句不存在Flipper或sort字段返回空字符串
*
* @param flipper 翻页对象
*
* @return String
*/
protected String createSQLOrderby(Flipper flipper) { protected String createSQLOrderby(Flipper flipper) {
if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty() || flipper.getSort().indexOf(';') >= 0 || flipper.getSort().indexOf('\n') >= 0) return ""; if (flipper == null || flipper.getSort() == null) return "";
final String sort = flipper.getSort(); final String sort = flipper.getSort();
if (sort.isEmpty() || sort.indexOf(';') >= 0 || sort.indexOf('\n') >= 0) return "";
String sql = this.sortOrderbySqls.get(sort); String sql = this.sortOrderbySqls.get(sort);
if (sql != null) return sql; if (sql != null) return sql;
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
@@ -409,21 +526,47 @@ public final class EntityInfo<T> {
return sql; return sql;
} }
//根据field字段名获取数据库对应的字段名 /**
* 根据field字段名获取数据库对应的字段名
*
* @param tabalis 表别名
* @param fieldname 字段名
*
* @return String
*/
public String getSQLColumn(String tabalis, String fieldname) { public String getSQLColumn(String tabalis, String fieldname) {
return this.aliasmap == null ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname)) return this.aliasmap == null ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname))
: (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname))); : (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname)));
} }
/**
* 获取主键字段的表字段名
*
* @return String
*/
public String getPrimarySQLColumn() { public String getPrimarySQLColumn() {
return getSQLColumn(null, this.primary.field()); return getSQLColumn(null, this.primary.field());
} }
//数据库字段名 /**
* 获取主键字段的带有表别名的表字段名
*
* @param tabalis 表别名
*
* @return String
*/
public String getPrimarySQLColumn(String tabalis) { public String getPrimarySQLColumn(String tabalis) {
return getSQLColumn(tabalis, this.primary.field()); return getSQLColumn(tabalis, this.primary.field());
} }
/**
* 拼接UPDATE给字段赋值的SQL片段
*
* @param col 表字段名
* @param cv ColumnValue
*
* @return CharSequence
*/
protected CharSequence formatSQLValue(String col, final ColumnValue cv) { protected CharSequence formatSQLValue(String col, final ColumnValue cv) {
if (cv == null) return null; if (cv == null) return null;
switch (cv.getExpress()) { switch (cv.getExpress()) {
@@ -441,14 +584,33 @@ public final class EntityInfo<T> {
return formatToString(cv.getValue()); return formatToString(cv.getValue());
} }
/**
* 获取所有数据表字段的Attribute, 不包含&#64;Transient字段
*
* @return Map
*/
protected Map<String, Attribute<T, Serializable>> getAttributes() { protected Map<String, Attribute<T, Serializable>> getAttributes() {
return attributeMap; return attributeMap;
} }
/**
* 判断日志级别
*
* @param l Level
*
* @return boolean
*/
public boolean isLoggable(Level l) { public boolean isLoggable(Level l) {
return l.intValue() >= this.logLevel; return l.intValue() >= this.logLevel;
} }
/**
* 将字段值序列化为可SQL的字符串
*
* @param value 字段值
*
* @return String
*/
protected String formatToString(Object value) { protected String formatToString(Object value) {
if (value == null) return null; if (value == null) return null;
if (value instanceof CharSequence) { if (value instanceof CharSequence) {
@@ -457,12 +619,30 @@ public final class EntityInfo<T> {
return String.valueOf(value); return String.valueOf(value);
} }
/**
* 将一行的ResultSet组装成一个Entity对象
*
* @param sels 指定字段
* @param set ResultSet
*
* @return Entity对象
* @throws SQLException SQLException
*/
protected T getValue(final SelectColumn sels, final ResultSet set) throws SQLException { protected T getValue(final SelectColumn sels, final ResultSet set) throws SQLException {
T obj = creator.create(); T obj = creator.create();
for (Attribute<T, Serializable> attr : queryAttributes) { for (Attribute<T, Serializable> attr : queryAttributes) {
if (sels == null || sels.test(attr.field())) { if (sels == null || sels.test(attr.field())) {
Serializable o = (Serializable) set.getObject(this.getSQLColumn(null, attr.field()));
final Class t = attr.type(); final Class t = attr.type();
Serializable o;
if (t == byte[].class) {
Blob blob = set.getBlob(this.getSQLColumn(null, attr.field()));
if (blob == null) {
o = null;
} else { //不支持超过2G的数据
o = blob.getBytes(1, (int) blob.length());
}
} else {
o = (Serializable) set.getObject(this.getSQLColumn(null, attr.field()));
if (t.isPrimitive()) { if (t.isPrimitive()) {
if (o != null) { if (o != null) {
if (t == int.class) { if (t == int.class) {
@@ -498,6 +678,7 @@ public final class EntityInfo<T> {
o = (char) 0; o = (char) 0;
} }
} }
}
attr.set(obj, o); attr.set(obj, o);
} }
} }

View File

@@ -3,14 +3,16 @@
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
package org.redkale.source; package org.redkale.source;
/** /**
* FilterBean用于过滤条件 所有的FilterBean都必须可以转换成FilterNode <br>
* *
* 不被标记为&#64;javax.persistence.Transient 的字段均视为过滤条件 * 不被标记为&#64;javax.persistence.Transient 的字段均视为过滤条件 <br>
*
* <p>
* 详情见: https://redkale.org
* *
* <p> 详情见: https://redkale.org
* @author zhangjx * @author zhangjx
*/ */
public interface FilterBean { public interface FilterBean {

View File

@@ -38,10 +38,10 @@ public @interface FilterColumn {
long least() default 1; long least() default 1;
/** /**
* express的默认值根据字段类型的不同而不同: * express的默认值根据字段类型的不同而不同: <br>
* 数组 --&gt; IN * 数组 --&gt; IN <br>
* Range --&gt; Between * Range --&gt; Between <br>
* 其他 --&gt; = * 其他 --&gt; = <br>
* *
* @return 字段表达式 * @return 字段表达式
*/ */
@@ -54,4 +54,11 @@ public @interface FilterColumn {
*/ */
boolean itemand() default true; boolean itemand() default true;
/**
* 备注描述
*
* @return 备注描述
*/
String comment() default "";
} }

View File

@@ -0,0 +1,93 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.source;
import java.util.Arrays;
/**
* FilterFuncColumn用于getNumberMap获取列表似数据, getNumberResult获取单字段值 getNumberMap获取多字段值
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class FilterFuncColumn implements java.io.Serializable {
public static final String COLUMN_NULL = "*";
FilterFunc func;
String[] columns; //为null将使用*代替
Number defvalue;
public FilterFuncColumn() {
}
public static FilterFuncColumn create(final FilterFunc func) {
return new FilterFuncColumn(func);
}
public static FilterFuncColumn create(final FilterFunc func, final String... columns) {
return new FilterFuncColumn(func, columns);
}
public static FilterFuncColumn create(final FilterFunc func, final Number defvalue, final String... columns) {
return new FilterFuncColumn(func, defvalue, columns);
}
String[] cols() {
return columns == null || columns.length == 0 ? new String[]{COLUMN_NULL} : columns;
}
String col(String column) {
return column == null || column.isEmpty() ? COLUMN_NULL : column;
}
public FilterFuncColumn(final FilterFunc func) {
this(func, (Number) null);
}
public FilterFuncColumn(final FilterFunc func, final String... columns) {
this(func, null, columns);
}
public FilterFuncColumn(final FilterFunc func, final Number defvalue, final String... columns) {
this.func = func;
this.defvalue = defvalue;
this.columns = columns;
}
public FilterFunc getFunc() {
return func;
}
public void setFunc(FilterFunc func) {
this.func = func;
}
public String[] getColumns() {
return columns;
}
public void setColumns(String[] columns) {
this.columns = columns;
}
public Number getDefvalue() {
return defvalue;
}
public void setDefvalue(Number defvalue) {
this.defvalue = defvalue;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{func:" + this.func + ", columns:" + Arrays.toString(this.columns) + ", defvalue:" + this.defvalue + "}";
}
}

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