Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54b7863be6 | ||
|
|
26453fe4c5 | ||
|
|
036b248092 | ||
|
|
8ca79face5 | ||
|
|
6fd3250fba | ||
|
|
93a213448a | ||
|
|
e12cf185d9 | ||
|
|
ca6c90eacd | ||
|
|
8901dd9a07 | ||
|
|
93fef97c56 | ||
|
|
ddef9018e2 | ||
|
|
fb51997c6b | ||
|
|
65da7118fc | ||
|
|
fc2dfa1a8a | ||
|
|
68db4e37e2 | ||
|
|
28c9b2606a | ||
|
|
d47b63e47b | ||
|
|
7f86972fa1 | ||
|
|
92eefc872a | ||
|
|
c43e516d14 | ||
|
|
8884fabf90 | ||
|
|
1720470424 | ||
|
|
1da2e95f46 | ||
|
|
940af0b251 | ||
|
|
43102b9d35 | ||
|
|
fa601c69e7 | ||
|
|
b365b18be0 | ||
|
|
bc8a52eef8 | ||
|
|
afa45498d4 | ||
|
|
6f056bbcb6 | ||
|
|
4fb218fd18 | ||
|
|
1e7575c7b7 | ||
|
|
02fd74f6de | ||
|
|
77732347d0 | ||
|
|
53eaad17ea | ||
|
|
4cdc1f82c5 | ||
|
|
77c2f72b42 | ||
|
|
469069d2ac | ||
|
|
d7542a0c0a | ||
|
|
15d36735da | ||
|
|
d3163a6e0d | ||
|
|
23fd664eef | ||
|
|
f21cb2c233 | ||
|
|
0a2a9f0e80 | ||
|
|
9b74f46b22 | ||
|
|
59ca4afd8b | ||
|
|
bc1c749152 | ||
|
|
d35987612d | ||
|
|
04b5b361ad | ||
|
|
a81c9f7d21 | ||
|
|
2c75c04b7e | ||
|
|
9bf5044654 | ||
|
|
e99fd3c049 | ||
|
|
4e9b3f45fc | ||
|
|
95f4cd0634 | ||
|
|
a43f9a0121 | ||
|
|
6f6952ad2c | ||
|
|
21cfbebe26 | ||
|
|
f16beca680 | ||
|
|
1341e81361 | ||
|
|
f08a29b15a | ||
|
|
fea5123915 | ||
|
|
cd45cafec5 | ||
|
|
bed86d44a1 | ||
|
|
bd3ae4bb41 | ||
|
|
589d34d8a4 | ||
|
|
a455795703 | ||
|
|
fbb9cdefe1 | ||
|
|
d202b2fbad | ||
|
|
9d82ca84a4 | ||
|
|
1f0e0accb1 | ||
|
|
fa8e40f6c0 | ||
|
|
1a22cd0fe1 | ||
|
|
8422173411 | ||
|
|
c63248ba7f | ||
|
|
de4dda7c73 | ||
|
|
e546ff74a5 | ||
|
|
506f930320 | ||
|
|
09beaedee8 | ||
|
|
40845f5f60 | ||
|
|
f3f001d72d | ||
|
|
b49a4d2c83 | ||
|
|
90884f4621 | ||
|
|
c2fd7be5e2 | ||
|
|
b1773107a1 | ||
|
|
f6aa646ea4 | ||
|
|
72887106ea | ||
|
|
aa6126ddec | ||
|
|
a98a35b4af | ||
|
|
07253b1f17 | ||
|
|
48a4c6d53c | ||
|
|
d78c08878c | ||
|
|
d40ea81fc3 | ||
|
|
78ac88b57c | ||
|
|
3595f8b6bc | ||
|
|
1421b83e49 | ||
|
|
90361edba1 | ||
|
|
3d3347b64f | ||
|
|
f8a439e21f | ||
|
|
9d76e693fb | ||
|
|
a206ecd76b | ||
|
|
81f386dcdb | ||
|
|
e8e6459679 | ||
|
|
9f5ab4b068 | ||
|
|
1ea816a60e | ||
|
|
2c5876ba3e | ||
|
|
cffe181344 | ||
|
|
4647545ff5 | ||
|
|
bfe78a805e | ||
|
|
c480b2b18e | ||
|
|
7e9885de2e | ||
|
|
db32656c8a | ||
|
|
b981307768 | ||
|
|
b0e0a341ec | ||
|
|
40ef40b813 | ||
|
|
dfacd49a70 | ||
|
|
470a82b6e6 | ||
|
|
d5a752dea0 | ||
|
|
554932201b | ||
|
|
54462e8c26 | ||
|
|
d9807148db | ||
|
|
66a5fc2447 | ||
|
|
4f9c8ce145 | ||
|
|
884cc930c8 | ||
|
|
cd4b18ad45 | ||
|
|
707fc783b5 | ||
|
|
3ca6ad6e12 | ||
|
|
4972f5804e | ||
|
|
aec69d2973 | ||
|
|
3f2a7f684f | ||
|
|
ce9f517244 | ||
|
|
192e52f18f | ||
|
|
cdbe53d3d9 | ||
|
|
58f4f28e14 | ||
|
|
bc19d75422 |
7
bin/apidoc.bat
Normal file
7
bin/apidoc.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
@ECHO OFF
|
||||
|
||||
SET APP_HOME=%~dp0
|
||||
|
||||
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
|
||||
|
||||
java -DCMD=APIDOC -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
|
||||
18
bin/apidoc.sh
Normal file
18
bin/apidoc.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
export LC_ALL="zh_CN.UTF-8"
|
||||
|
||||
APP_HOME=`dirname "$0"`
|
||||
|
||||
if [ ! -a "$APP_HOME"/conf/application.xml ]; then
|
||||
APP_HOME="$APP_HOME"/..
|
||||
fi
|
||||
|
||||
lib='.'
|
||||
for jar in `ls $APP_HOME/lib/*.jar`
|
||||
do
|
||||
lib=$lib:$jar
|
||||
done
|
||||
export CLASSPATH=$CLASSPATH:$lib
|
||||
echo "$APP_HOME"
|
||||
java -DCMD=APIDOC -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
|
||||
@@ -4,4 +4,4 @@ SET APP_HOME=%~dp0
|
||||
|
||||
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
|
||||
|
||||
java -DSHUTDOWN=true -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
|
||||
java -DCMD=SHUTDOWN -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
|
||||
|
||||
@@ -15,4 +15,4 @@ do
|
||||
done
|
||||
export CLASSPATH=$CLASSPATH:$lib
|
||||
echo "$APP_HOME"
|
||||
java -DSHUTDOWN=true -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
|
||||
java -DCMD=SHUTDOWN -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<!--
|
||||
文件说明:
|
||||
${APP_HOME} 指当前程序的根目录APP_HOME
|
||||
没注明唯一的节点可多个存在
|
||||
required: 被声明required的属性值不能为空
|
||||
|
||||
group
|
||||
@@ -18,27 +19,31 @@
|
||||
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
|
||||
-->
|
||||
<!--
|
||||
address: 本地的IP地址, 默认值为默认网卡的ip,当不使用默认值需要指定值,如127.0.0.1
|
||||
address: 本地局域网的IP地址, 默认值为默认网卡的ip,当不使用默认值需要指定值,如192.168.1.22
|
||||
port: required 程序的管理Server的端口,用于关闭或者与监管系统进行数据交互
|
||||
host: 程序的管理Server的地址; 默认为127.0.0.1。
|
||||
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
|
||||
-->
|
||||
<application port="6560" lib="">
|
||||
|
||||
<!-- 所有服务所需的资源 -->
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
所有服务所需的资源
|
||||
-->
|
||||
<resources>
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
||||
threads: 线程总数, 默认: <group>节点数*CPU核数*8
|
||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 8K;
|
||||
bufferPoolSize: ByteBuffer池的大小,默认: <group>节点数*CPU核数*8
|
||||
-->
|
||||
<transport capacity="8192" bufferPoolSize="32" threads="32"/>
|
||||
<transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/>
|
||||
<!--
|
||||
一个组包含多个NODE, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
||||
一个group节点对应一个 Transport 对象。
|
||||
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
||||
protocol:值只能是UDP TCP, 默认TCP
|
||||
kind: 与SNCP服务连接时的数据传输类型;可选值有:rest(不区分大小写);值为空或空字符串表示按SNCP协议传输; 为rest表示按REST传输。默认值为空
|
||||
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
||||
-->
|
||||
<group name="" protocol="TCP">
|
||||
@@ -53,6 +58,7 @@
|
||||
<node addr="127.0.0.1" port="7070"/>
|
||||
</group>
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入, 被注解的字段类型只能是String、primitive class
|
||||
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
||||
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
||||
@@ -79,6 +85,7 @@
|
||||
port: required 服务所占端口
|
||||
root: 如果是web类型服务,则包含页面 默认:{APP_HOME}/root
|
||||
lib: server额外的class目录, 默认为空
|
||||
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||
charset: 文本编码, 默认: UTF-8
|
||||
backlog: 默认10K
|
||||
threads: 线程总数, 默认: CPU核数*16
|
||||
@@ -122,6 +129,24 @@
|
||||
</services>
|
||||
|
||||
<!--
|
||||
REST的核心配置项
|
||||
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个
|
||||
base: REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
|
||||
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
|
||||
mustsign:默认值"true" 是否只加载标记为RestService的Service类,默认只加载标记RestService且ignore=false的Service
|
||||
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||
-->
|
||||
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="false" autoload="true" includes="" excludes="">
|
||||
<!--
|
||||
value: Service类名,列出的表示必须被加载的Service对象
|
||||
ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
|
||||
-->
|
||||
<service value="com.xxx.XXXXService"/>
|
||||
</rest>
|
||||
|
||||
<!--
|
||||
【节点在<server>中唯一】
|
||||
当Server为HTTP协议时, request节点才有效。
|
||||
remoteaddr 节点: 替换请求方节点的IP地址, 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。
|
||||
且value值只能是以request.headers.开头,表示从request.headers中获取对应的header值。
|
||||
@@ -132,6 +157,7 @@
|
||||
</request>
|
||||
|
||||
<!--
|
||||
【节点在<server>中唯一】
|
||||
当Server为HTTP协议时, response节点才有效。
|
||||
defcookie 节点: 当response里输出的cookie没有指定domain 和path时,使用该节点的默认值。
|
||||
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
|
||||
@@ -145,26 +171,19 @@
|
||||
</response>
|
||||
|
||||
<!--
|
||||
加载所有的Servlet服务;
|
||||
path: servlet的ContextPath前缀 默认为空
|
||||
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Servlet类:
|
||||
${APP_HOME}/lib; ${APP_HOME}/root/lib/*; ${APP_HOME}/root/classes;
|
||||
autoload="false" 需要显著的指定Service类
|
||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||
-->
|
||||
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
||||
<!--
|
||||
【节点在<server>中唯一】
|
||||
当Server为HTTP协议时,ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
|
||||
webroot: web资源的根目录, 默认取server节点中的root值
|
||||
servlet: 静态资源HttpServlet的实现,默认使用HttpResourceServlet
|
||||
index : 启始页,默认值:index.html
|
||||
-->
|
||||
<resource-servlet webroot="root" index="index.html">
|
||||
<!--
|
||||
【节点在<resource-servlet>中唯一】
|
||||
资源缓存的配置, 默认存在一个含默认属性的caches节点
|
||||
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存, 单位可以是B、K、M、G,不区分大小写
|
||||
lengthmax: 可缓存的文件大小上限, 默认: 1M(超过1M的文件不会被缓存)
|
||||
watch: 是否监控缓存文件的变化, 默认不监控
|
||||
watch: 是否监控缓存文件的变化, 默认为false,不监控
|
||||
-->
|
||||
<cache limit="0M" lengthmax="1M" watch="false"/>
|
||||
<!--
|
||||
@@ -176,6 +195,16 @@
|
||||
-->
|
||||
<rewrite type="location" match="^/([^-]+)-[^-\.]+\.html(.*)" forward="/$1.html"/>
|
||||
</resource-servlet>
|
||||
<!--
|
||||
加载所有的Servlet服务;
|
||||
path: servlet的ContextPath前缀 默认为空
|
||||
autoload="true" 默认值. 自动加载以下目录(如果存在的话)下所有的Servlet类:
|
||||
${APP_HOME}/lib; ${APP_HOME}/root/lib/*; ${APP_HOME}/root/classes;
|
||||
autoload="false" 需要显著的指定Service类
|
||||
includes: 当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||
excludes: 当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
|
||||
-->
|
||||
<servlets path="/pipes" autoload="true" includes="" excludes="">
|
||||
<!-- 显著加载指定的Servlet -->
|
||||
<servlet value="com.xxx.XXX1Servlet" />
|
||||
<servlet value="com.xxx.XXX2Servlet" />
|
||||
|
||||
47
src/META-INF/persistence-template.xml
Normal file
47
src/META-INF/persistence-template.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
|
||||
<persistence>
|
||||
<!-- 系统基本库 -->
|
||||
<persistence-unit name="demouser">
|
||||
<!-- 为NONE表示不启动缓存,@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
|
||||
<shared-cache-mode>NONE</shared-cache-mode>
|
||||
<properties>
|
||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
|
||||
<!--
|
||||
javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。
|
||||
为了兼容用户习惯,Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系:
|
||||
com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
|
||||
org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource
|
||||
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
|
||||
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
|
||||
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
|
||||
-->
|
||||
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||
<property name="javax.persistence.jdbc.password" value="123456"/>
|
||||
|
||||
<!-- 最大连接数,默认值:CPU数*16 -->
|
||||
<property name="javax.persistence.connections.limit" value="32"/>
|
||||
|
||||
<!-- 包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL、Oracle、Sqlserver的语句 -->
|
||||
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
|
||||
<property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
|
||||
|
||||
<!-- 复制表结构的SQL模板,Redkale内置了MySQL的语句 -->
|
||||
<property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
|
||||
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
|
||||
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
<!-- IM消息库 -->
|
||||
<persistence-unit name="demoim">
|
||||
<shared-cache-mode>NONE</shared-cache-mode>
|
||||
<properties>
|
||||
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&autoReconnectForPools=true&characterEncoding=utf8 -->
|
||||
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
|
||||
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
|
||||
<property name="javax.persistence.jdbc.user" value="root"/>
|
||||
<property name="javax.persistence.jdbc.password" value="123456"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
146
src/org/redkale/boot/ApiDocs.java
Normal file
146
src/org/redkale/boot/ApiDocs.java
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.boot;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.net.http.*;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* 继承 HttpBaseServlet 是为了获取 WebAction 信息
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class ApiDocs extends HttpBaseServlet {
|
||||
|
||||
private final Application app;
|
||||
|
||||
public ApiDocs(Application app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
List<Map> serverList = new ArrayList<>();
|
||||
|
||||
Map<String, Map<String, Map<String, String>>> typesmap = new LinkedHashMap<>();
|
||||
for (NodeServer node : app.servers) {
|
||||
if (!(node instanceof NodeHttpServer)) continue;
|
||||
final Map<String, Object> map = new LinkedHashMap<>();
|
||||
serverList.add(map);
|
||||
HttpServer server = node.getServer();
|
||||
map.put("address", server.getSocketAddress());
|
||||
List<Map<String, Object>> servletsList = new ArrayList<>();
|
||||
map.put("servlets", servletsList);
|
||||
for (HttpServlet servlet : server.getPrepareServlet().getServlets()) {
|
||||
if (!(servlet instanceof HttpServlet)) continue;
|
||||
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||
if (ws == null) {
|
||||
System.err.println(servlet + " not found @WebServlet");
|
||||
continue;
|
||||
}
|
||||
final Map<String, Object> servletmap = new LinkedHashMap<>();
|
||||
String prefix = _prefix(servlet);
|
||||
String[] mappings = ws.value();
|
||||
if (prefix != null && !prefix.isEmpty()) {
|
||||
for (int i = 0; i < mappings.length; i++) {
|
||||
mappings[i] = prefix + mappings[i];
|
||||
}
|
||||
}
|
||||
servletmap.put("mappings", mappings);
|
||||
servletmap.put("moduleid", ws.moduleid());
|
||||
servletmap.put("name", ws.name());
|
||||
servletmap.put("comment", ws.comment());
|
||||
|
||||
List<Map> actionsList = new ArrayList<>();
|
||||
servletmap.put("actions", actionsList);
|
||||
for (Method method : servlet.getClass().getMethods()) {
|
||||
if (method.getParameterCount() != 2) continue;
|
||||
WebAction action = method.getAnnotation(WebAction.class);
|
||||
if (action == null) continue;
|
||||
final Map<String, Object> actionmap = new LinkedHashMap<>();
|
||||
actionmap.put("url", prefix + action.url());
|
||||
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
|
||||
actionmap.put("actionid", action.actionid());
|
||||
actionmap.put("comment", action.comment());
|
||||
List<Map> paramsList = new ArrayList<>();
|
||||
actionmap.put("params", paramsList);
|
||||
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
|
||||
final Map<String, Object> parammap = new LinkedHashMap<>();
|
||||
final boolean isarray = param.type().isArray();
|
||||
final Class ptype = isarray ? param.type().getComponentType() : param.type();
|
||||
parammap.put("name", param.name());
|
||||
parammap.put("radix", param.radix());
|
||||
parammap.put("type", ptype.getName() + (isarray ? "[]" : ""));
|
||||
parammap.put("src", param.src());
|
||||
parammap.put("comment", param.comment());
|
||||
paramsList.add(parammap);
|
||||
if (ptype.isPrimitive() || ptype == String.class) continue;
|
||||
if (typesmap.containsKey(ptype.getName())) continue;
|
||||
|
||||
final Map<String, Map<String, String>> typemap = new LinkedHashMap<>();
|
||||
Class loop = ptype;
|
||||
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, String> fieldmap = new LinkedHashMap<>();
|
||||
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
|
||||
|
||||
Comment comment = field.getAnnotation(Comment.class);
|
||||
if (comment != null) fieldmap.put("comment", comment.value());
|
||||
|
||||
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(ptype.getName(), typemap);
|
||||
}
|
||||
actionmap.put("result", action.result());
|
||||
actionsList.add(actionmap);
|
||||
}
|
||||
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
|
||||
servletsList.add(servletmap);
|
||||
}
|
||||
servletsList.sort((o1, o2) -> {
|
||||
String[] mappings1 = (String[]) o1.get("mappings");
|
||||
String[] mappings2 = (String[]) o2.get("mappings");
|
||||
return mappings1.length > 0 ? (mappings2.length > 0 ? mappings1[0].compareTo(mappings2[0]) : 1) : -1;
|
||||
});
|
||||
}
|
||||
Map<String, Object> resultmap = new LinkedHashMap<>();
|
||||
resultmap.put("servers", serverList);
|
||||
resultmap.put("types", typesmap);
|
||||
final String json = JsonConvert.root().convertTo(resultmap);
|
||||
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
|
||||
out.write(json.getBytes("UTF-8"));
|
||||
out.close();
|
||||
File doctemplate = new File(app.getHome(), "conf/apidoc-template.html");
|
||||
InputStream in = null;
|
||||
if (doctemplate.isFile() && doctemplate.canRead()) {
|
||||
in = new FileInputStream(doctemplate);
|
||||
}
|
||||
if (in == null) in = ApiDocs.class.getResourceAsStream("apidoc-template.html");
|
||||
String content = Utility.read(in).replace("${content}", json);
|
||||
in.close();
|
||||
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
|
||||
outhtml.write(content.getBytes("UTF-8"));
|
||||
outhtml.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -65,9 +65,7 @@ public final class Application {
|
||||
|
||||
final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
|
||||
|
||||
final Map<String, Set<InetSocketAddress>> globalGroups = new HashMap<>();
|
||||
|
||||
final Map<String, String> globalGroupProtocols = new HashMap<>();
|
||||
final Map<String, GroupInfo> globalGroups = new HashMap<>();
|
||||
|
||||
final InetAddress localAddress;
|
||||
|
||||
@@ -77,8 +75,6 @@ public final class Application {
|
||||
|
||||
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
|
||||
|
||||
CountDownLatch servicecdl; //会出现两次赋值
|
||||
|
||||
final ObjectPool<ByteBuffer> transportBufferPool;
|
||||
|
||||
final ExecutorService transportExecutor;
|
||||
@@ -87,6 +83,8 @@ public final class Application {
|
||||
|
||||
final ResourceFactory resourceFactory = ResourceFactory.root();
|
||||
|
||||
CountDownLatch servicecdl; //会出现两次赋值
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
private final boolean singletonrun;
|
||||
|
||||
@@ -331,15 +329,14 @@ public final class Application {
|
||||
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
|
||||
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
|
||||
}
|
||||
Set<InetSocketAddress> addrs = globalGroups.get(group);
|
||||
if (addrs == null) {
|
||||
addrs = new LinkedHashSet<>();
|
||||
globalGroupProtocols.put(group, protocol);
|
||||
globalGroups.put(group, addrs);
|
||||
GroupInfo ginfo = globalGroups.get(group);
|
||||
if (ginfo == null) {
|
||||
ginfo = new GroupInfo(group, protocol, conf.getValue("kind", ""), new LinkedHashSet<>());
|
||||
globalGroups.put(group, ginfo);
|
||||
}
|
||||
for (AnyValue node : conf.getAnyValues("node")) {
|
||||
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
|
||||
addrs.add(addr);
|
||||
ginfo.addrs.add(addr);
|
||||
String oldgroup = globalNodes.get(addr);
|
||||
if (oldgroup != null) throw new RuntimeException(addr + " had one more group " + (globalNodes.get(addr)));
|
||||
globalNodes.put(addr, group);
|
||||
@@ -362,7 +359,7 @@ public final class Application {
|
||||
final DatagramChannel channel = DatagramChannel.open();
|
||||
channel.configureBlocking(true);
|
||||
channel.socket().setSoTimeout(3000);
|
||||
channel.bind(new InetSocketAddress(config.getValue("host", "127.0.0.1"), config.getIntValue("port")));
|
||||
channel.bind(new InetSocketAddress("127.0.0.1", config.getIntValue("port")));
|
||||
boolean loop = true;
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
|
||||
while (loop) {
|
||||
@@ -391,6 +388,19 @@ public final class Application {
|
||||
buffer.flip();
|
||||
channel.send(buffer, address);
|
||||
}
|
||||
} else if ("APIDOC".equalsIgnoreCase(new String(bytes))) {
|
||||
try {
|
||||
new ApiDocs(application).run();
|
||||
buffer.clear();
|
||||
buffer.put("APIDOC OK".getBytes());
|
||||
buffer.flip();
|
||||
channel.send(buffer, address);
|
||||
} catch (Exception ex) {
|
||||
buffer.clear();
|
||||
buffer.put("APIDOC FAIL".getBytes());
|
||||
buffer.flip();
|
||||
channel.send(buffer, address);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -401,12 +411,12 @@ public final class Application {
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void sendShutDown() throws Exception {
|
||||
private void sendCommand(String command) throws Exception {
|
||||
final DatagramChannel channel = DatagramChannel.open();
|
||||
channel.configureBlocking(true);
|
||||
channel.connect(new InetSocketAddress(config.getValue("host", "127.0.0.1"), config.getIntValue("port")));
|
||||
channel.connect(new InetSocketAddress("127.0.0.1", config.getIntValue("port")));
|
||||
ByteBuffer buffer = ByteBuffer.allocate(128);
|
||||
buffer.put("SHUTDOWN".getBytes());
|
||||
buffer.put(command.getBytes());
|
||||
buffer.flip();
|
||||
channel.write(buffer);
|
||||
buffer.clear();
|
||||
@@ -464,15 +474,15 @@ public final class Application {
|
||||
final String protocol = serconf.getValue("protocol", "").replaceFirst("\\..+", "").toUpperCase();
|
||||
NodeServer server = null;
|
||||
if ("SNCP".equals(protocol)) {
|
||||
server = new NodeSncpServer(Application.this, serconf);
|
||||
} else if ("HTTP".equals(protocol)) {
|
||||
server = NodeSncpServer.createNodeServer(Application.this, serconf);
|
||||
} else if ("HTTP".equalsIgnoreCase(protocol)) {
|
||||
server = new NodeHttpServer(Application.this, serconf);
|
||||
} else {
|
||||
if (!inited.get()) {
|
||||
synchronized (nodeClasses) {
|
||||
if (!inited.getAndSet(true)) { //加载自定义的协议,如:SOCKS
|
||||
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class);
|
||||
ClassFilter.Loader.load(home, profilter);
|
||||
ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter);
|
||||
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
|
||||
for (FilterEntry<NodeServer> entry : entrys) {
|
||||
final Class<? extends NodeServer> type = entry.getType();
|
||||
@@ -537,8 +547,11 @@ public final class Application {
|
||||
Utility.midnight(); //先初始化一下Utility
|
||||
//运行主程序
|
||||
final Application application = Application.create(false);
|
||||
if (System.getProperty("SHUTDOWN") != null) {
|
||||
application.sendShutDown();
|
||||
if (System.getProperty("CMD") != null) {
|
||||
application.sendCommand(System.getProperty("CMD"));
|
||||
return;
|
||||
} else if (System.getProperty("SHUTDOWN") != null) { //兼容旧接口
|
||||
application.sendCommand("SHUTDOWN");
|
||||
return;
|
||||
}
|
||||
application.init();
|
||||
@@ -572,15 +585,9 @@ public final class Application {
|
||||
return null;
|
||||
}
|
||||
|
||||
String findGroupProtocol(String group) {
|
||||
GroupInfo findGroupInfo(String group) {
|
||||
if (group == null) return null;
|
||||
return globalGroupProtocols.get(group);
|
||||
}
|
||||
|
||||
Set<InetSocketAddress> findGlobalGroup(String group) {
|
||||
if (group == null) return null;
|
||||
Set<InetSocketAddress> set = globalGroups.get(group);
|
||||
return set == null ? null : new LinkedHashSet<>(set);
|
||||
return globalGroups.get(group);
|
||||
}
|
||||
|
||||
private void shutdown() throws Exception {
|
||||
|
||||
@@ -32,25 +32,29 @@ public final class ClassFilter<T> {
|
||||
|
||||
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<>(); //符合条件的结果
|
||||
|
||||
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>();
|
||||
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
|
||||
|
||||
private boolean refused;
|
||||
private boolean refused; //是否拒绝所有数据,设置true,则其他规则失效,都是拒绝.
|
||||
|
||||
private Class superClass;
|
||||
private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类
|
||||
|
||||
private Class<? extends Annotation> annotationClass;
|
||||
private Class<? extends Annotation> annotationClass;//符合的注解。不为空时,扫描结果的class必须包含该注解
|
||||
|
||||
private Pattern[] includePatterns;
|
||||
private Pattern[] includePatterns; //符合的classname正则表达式
|
||||
|
||||
private Pattern[] excludePatterns;
|
||||
private Pattern[] excludePatterns;//拒绝的classname正则表达式
|
||||
|
||||
private List<ClassFilter> ors;
|
||||
private Set<String> privilegeIncludes; //特批符合条件的classname
|
||||
|
||||
private List<ClassFilter> ands;
|
||||
private Set<String> privilegeExcludes;//特批拒绝条件的classname
|
||||
|
||||
private AnyValue conf;
|
||||
private List<ClassFilter> ors; //或关系的其他ClassFilter
|
||||
|
||||
private List<ClassFilter> ands;//与关系的其他ClassFilter
|
||||
|
||||
private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。
|
||||
|
||||
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass) {
|
||||
this(annotationClass, superClass, null);
|
||||
@@ -62,6 +66,15 @@ public final class ClassFilter<T> {
|
||||
this.conf = conf;
|
||||
}
|
||||
|
||||
public static ClassFilter create(String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
|
||||
ClassFilter filter = new ClassFilter(null, null);
|
||||
filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";"));
|
||||
filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";"));
|
||||
filter.setPrivilegeIncludes(includeValues);
|
||||
filter.setPrivilegeExcludes(excludeValues);
|
||||
return filter;
|
||||
}
|
||||
|
||||
public ClassFilter<T> or(ClassFilter<T> filter) {
|
||||
if (ors == null) ors = new ArrayList<>();
|
||||
ors.add(filter);
|
||||
@@ -164,24 +177,20 @@ public final class ClassFilter<T> {
|
||||
} catch (Throwable cfe) {
|
||||
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
|
||||
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) {
|
||||
logger.log(Level.FINER, ClassFilter.class.getSimpleName() + " filter error", cfe);
|
||||
//logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Pattern[] toPattern(String[] regs) {
|
||||
if (regs == null) return null;
|
||||
int i = 0;
|
||||
Pattern[] rs = new Pattern[regs.length];
|
||||
for (String reg : regs) {
|
||||
if (reg == null || reg.trim().isEmpty()) continue;
|
||||
rs[i++] = Pattern.compile(reg.trim());
|
||||
}
|
||||
if (i == 0) return null;
|
||||
if (i == rs.length) return rs;
|
||||
Pattern[] ps = new Pattern[i];
|
||||
System.arraycopy(rs, 0, ps, 0, i);
|
||||
return ps;
|
||||
/**
|
||||
* 判断class是否有效
|
||||
*
|
||||
* @param classname String
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean accept(String classname) {
|
||||
return accept(null, classname);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,6 +218,8 @@ public final class ClassFilter<T> {
|
||||
|
||||
private boolean accept0(AnyValue property, String classname) {
|
||||
if (this.refused) return false;
|
||||
if (this.privilegeIncludes != null && this.privilegeIncludes.contains(classname)) return true;
|
||||
if (this.privilegeExcludes != null && this.privilegeExcludes.contains(classname)) return false;
|
||||
if (classname.startsWith("java.") || classname.startsWith("javax.")) return false;
|
||||
if (excludePatterns != null) {
|
||||
for (Pattern reg : excludePatterns) {
|
||||
@@ -239,6 +250,21 @@ public final class ClassFilter<T> {
|
||||
return superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
|
||||
}
|
||||
|
||||
public static Pattern[] toPattern(String[] regs) {
|
||||
if (regs == null || regs.length == 0) return null;
|
||||
int i = 0;
|
||||
Pattern[] rs = new Pattern[regs.length];
|
||||
for (String reg : regs) {
|
||||
if (reg == null || reg.trim().isEmpty()) continue;
|
||||
rs[i++] = Pattern.compile(reg.trim());
|
||||
}
|
||||
if (i == 0) return null;
|
||||
if (i == rs.length) return rs;
|
||||
Pattern[] ps = new Pattern[i];
|
||||
System.arraycopy(rs, 0, ps, 0, i);
|
||||
return ps;
|
||||
}
|
||||
|
||||
public void setSuperClass(Class superClass) {
|
||||
this.superClass = superClass;
|
||||
}
|
||||
@@ -279,6 +305,22 @@ public final class ClassFilter<T> {
|
||||
this.refused = refused;
|
||||
}
|
||||
|
||||
public Set<String> getPrivilegeIncludes() {
|
||||
return privilegeIncludes;
|
||||
}
|
||||
|
||||
public void setPrivilegeIncludes(Set<String> privilegeIncludes) {
|
||||
this.privilegeIncludes = privilegeIncludes == null || privilegeIncludes.isEmpty() ? null : privilegeIncludes;
|
||||
}
|
||||
|
||||
public Set<String> getPrivilegeExcludes() {
|
||||
return privilegeExcludes;
|
||||
}
|
||||
|
||||
public void setPrivilegeExcludes(Set<String> privilegeExcludes) {
|
||||
this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存放符合条件的class与class指定的属性项
|
||||
*
|
||||
@@ -379,18 +421,30 @@ public final class ClassFilter<T> {
|
||||
/**
|
||||
* 加载当前线程的classpath扫描所有class进行过滤
|
||||
*
|
||||
* @param exclude 不需要扫描的文件夹, 可以为null
|
||||
* @param excludeFile 不需要扫描的文件夹, 可以为null
|
||||
* @param excludeRegs 包含此关键字的文件将被跳过, 可以为null
|
||||
* @param filters 过滤器
|
||||
*
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public static void load(final File exclude, final ClassFilter... filters) throws IOException {
|
||||
public static void load(final File excludeFile, final String[] excludeRegs, final ClassFilter... filters) throws IOException {
|
||||
URLClassLoader loader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
|
||||
List<URL> urlfiles = new ArrayList<>(2);
|
||||
List<URL> urljares = new ArrayList<>(2);
|
||||
final URL exurl = exclude != null ? exclude.toURI().toURL() : null;
|
||||
final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null;
|
||||
final Pattern[] excludePatterns = toPattern(excludeRegs);
|
||||
for (URL url : loader.getURLs()) {
|
||||
if (exurl != null && exurl.sameFile(url)) continue;
|
||||
if (excludePatterns != null) {
|
||||
boolean skip = false;
|
||||
for (Pattern p : excludePatterns) {
|
||||
if (p.matcher(url.toString()).matches()) {
|
||||
skip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
}
|
||||
if (url.getPath().endsWith(".jar")) {
|
||||
urljares.add(url);
|
||||
} else {
|
||||
@@ -435,7 +489,7 @@ public final class ClassFilter<T> {
|
||||
files.clear();
|
||||
File root = new File(url.getFile());
|
||||
String rootpath = root.getPath();
|
||||
loadClassFiles(exclude, root, files);
|
||||
loadClassFiles(excludeFile, root, files);
|
||||
for (File f : files) {
|
||||
String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.');
|
||||
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
|
||||
|
||||
74
src/org/redkale/boot/GroupInfo.java
Normal file
74
src/org/redkale/boot/GroupInfo.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.boot;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class GroupInfo {
|
||||
|
||||
protected String name;
|
||||
|
||||
protected String protocol;
|
||||
|
||||
protected String kind;
|
||||
|
||||
protected Set<InetSocketAddress> addrs;
|
||||
|
||||
public GroupInfo() {
|
||||
}
|
||||
|
||||
public GroupInfo(String name, String protocol, String kind, Set<InetSocketAddress> addrs) {
|
||||
this.name = name;
|
||||
this.protocol = protocol;
|
||||
this.kind = kind;
|
||||
this.addrs = addrs;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public void setKind(String kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public Set<InetSocketAddress> getAddrs() {
|
||||
return addrs;
|
||||
}
|
||||
|
||||
public Set<InetSocketAddress> copyAddrs() {
|
||||
return addrs == null ? null : new LinkedHashSet<>(addrs);
|
||||
}
|
||||
|
||||
public void setAddrs(Set<InetSocketAddress> addrs) {
|
||||
this.addrs = addrs;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,13 +27,16 @@ import org.redkale.util.*;
|
||||
* @author zhangjx
|
||||
*/
|
||||
@NodeProtocol({"HTTP"})
|
||||
public final class NodeHttpServer extends NodeServer {
|
||||
public class NodeHttpServer extends NodeServer {
|
||||
|
||||
private final HttpServer httpServer;
|
||||
protected final boolean rest;
|
||||
|
||||
protected final HttpServer httpServer;
|
||||
|
||||
public NodeHttpServer(Application application, AnyValue serconf) {
|
||||
super(application, createServer(application, serconf));
|
||||
this.httpServer = (HttpServer) server;
|
||||
this.rest = serconf == null ? false : serconf.getAnyValue("rest") != null;
|
||||
}
|
||||
|
||||
private static Server createServer(Application application, AnyValue serconf) {
|
||||
@@ -84,9 +87,9 @@ public final class NodeHttpServer extends NodeServer {
|
||||
}, WebSocketNode.class);
|
||||
}
|
||||
|
||||
protected void loadHttpServlet(final AnyValue conf, final ClassFilter<? extends Servlet> filter) throws Exception {
|
||||
protected void loadHttpServlet(final AnyValue servletsConf, final ClassFilter<? extends Servlet> filter) throws Exception {
|
||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||
final String prefix = conf == null ? "" : conf.getValue("path", "");
|
||||
final String prefix = servletsConf == null ? "" : servletsConf.getValue("path", "");
|
||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||
List<FilterEntry<? extends Servlet>> list = new ArrayList(filter.getFilterEntrys());
|
||||
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载, 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
|
||||
@@ -121,7 +124,76 @@ public final class NodeHttpServer extends NodeServer {
|
||||
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings));
|
||||
}
|
||||
}
|
||||
if (ss != null && sb != null) {
|
||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||
int max = 0;
|
||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||
if (as.getKey().length() > max) max = as.getKey().length();
|
||||
}
|
||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||
sb.append(threadName).append(" Loaded ").append(as.getKey());
|
||||
for (int i = 0; i < max - as.getKey().length(); i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||
if (rest && serverConf != null) {
|
||||
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
|
||||
loadRestServlet(prefix, restConf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadRestServlet(final String prefix, final AnyValue restConf) throws Exception {
|
||||
if (!rest) return;
|
||||
if (restConf == null) return; //不存在REST服务
|
||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
|
||||
|
||||
final Class baseServletClass = Class.forName(restConf.getValue("base", DefaultRestServlet.class.getName()));
|
||||
|
||||
final boolean autoload = restConf.getBoolValue("autoload", true);
|
||||
final boolean mustsign = restConf.getBoolValue("mustsign", true); //是否只加载标记@RestService的Service类
|
||||
|
||||
final Set<String> includeValues = new HashSet<>();
|
||||
final Set<String> excludeValues = new HashSet<>();
|
||||
for (AnyValue item : restConf.getAnyValues("service")) {
|
||||
if (item.getBoolValue("ignore", false)) {
|
||||
excludeValues.add(item.getValue("value", ""));
|
||||
} else {
|
||||
includeValues.add(item.getValue("value", ""));
|
||||
}
|
||||
}
|
||||
|
||||
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
|
||||
|
||||
super.interceptorServiceWrappers.forEach((wrapper) -> {
|
||||
final Class stype = wrapper.getType();
|
||||
RestService rs = (RestService) stype.getAnnotation(RestService.class);
|
||||
if (rs != null && rs.ignore()) return;
|
||||
if (mustsign && rs == null) return;
|
||||
if (stype.getAnnotation(LocalService.class) != null && rs == null) return;
|
||||
|
||||
final String stypename = stype.getName();
|
||||
if (!autoload && !includeValues.contains(stypename)) return;
|
||||
if (!restFilter.accept(stypename)) return;
|
||||
|
||||
RestHttpServlet servlet = httpServer.addRestServlet(wrapper.getName(), stype, wrapper.getService(), baseServletClass, prefix, (AnyValue) null);
|
||||
resourceFactory.inject(servlet, NodeHttpServer.this);
|
||||
if (finest) logger.finest("Create RestServlet[resource=" + wrapper.getName() + "] = " + servlet);
|
||||
if (ss != null) {
|
||||
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||
for (int i = 0; i < mappings.length; i++) {
|
||||
mappings[i] = prefix + mappings[i];
|
||||
}
|
||||
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
|
||||
}
|
||||
});
|
||||
//输出信息
|
||||
if (ss != null && sb != null) {
|
||||
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
|
||||
int max = 0;
|
||||
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
|
||||
@@ -137,5 +209,4 @@ public final class NodeHttpServer extends NodeServer {
|
||||
}
|
||||
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
package org.redkale.boot;
|
||||
|
||||
import java.io.*;
|
||||
import static java.lang.Class.forName;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.*;
|
||||
import java.util.logging.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -48,9 +47,12 @@ public abstract class NodeServer {
|
||||
//日志是否为FINE级别
|
||||
protected final boolean fine;
|
||||
|
||||
//日志是否为FINE级别
|
||||
//日志是否为FINER级别
|
||||
protected final boolean finer;
|
||||
|
||||
//日志是否为FINEST级别
|
||||
protected final boolean finest;
|
||||
|
||||
//进程主类
|
||||
protected final Application application;
|
||||
|
||||
@@ -91,6 +93,7 @@ public abstract class NodeServer {
|
||||
this.logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
this.fine = logger.isLoggable(Level.FINE);
|
||||
this.finer = logger.isLoggable(Level.FINER);
|
||||
this.finest = logger.isLoggable(Level.FINEST);
|
||||
}
|
||||
|
||||
protected Consumer<Runnable> getExecutor() throws Exception {
|
||||
@@ -162,7 +165,7 @@ public abstract class NodeServer {
|
||||
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
|
||||
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
||||
if (!interceptorClass.isEmpty()) {
|
||||
Class clazz = forName(interceptorClass);
|
||||
Class clazz = Class.forName(interceptorClass);
|
||||
this.interceptor = (NodeInterceptor) clazz.newInstance();
|
||||
}
|
||||
|
||||
@@ -170,9 +173,9 @@ public abstract class NodeServer {
|
||||
ClassFilter<Service> serviceFilter = createServiceClassFilter();
|
||||
long s = System.currentTimeMillis();
|
||||
if (servletFilter == null) {
|
||||
ClassFilter.Loader.load(application.getHome(), serviceFilter);
|
||||
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter);
|
||||
} else {
|
||||
ClassFilter.Loader.load(application.getHome(), serviceFilter, servletFilter);
|
||||
ClassFilter.Loader.load(application.getHome(), serverConf.getValue("excludelibs", "").split(";"), serviceFilter, servletFilter);
|
||||
}
|
||||
long e = System.currentTimeMillis() - s;
|
||||
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
|
||||
@@ -234,6 +237,7 @@ public abstract class NodeServer {
|
||||
source.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class);
|
||||
if (field.getAnnotation(Transient.class) != null) source.setNeedStore(false); //必须在setStoreType之后
|
||||
application.cacheSources.add(source);
|
||||
appResFactory.register(resourceName, genericType, source);
|
||||
appResFactory.register(resourceName, CacheSource.class, source);
|
||||
field.set(src, source);
|
||||
rf.inject(source, self); //
|
||||
@@ -243,7 +247,7 @@ public abstract class NodeServer {
|
||||
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
|
||||
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
|
||||
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, sncpServer.getSncpGroup(), gs, null);
|
||||
sncpServer.getSncpServer().addService(wrapper);
|
||||
sncpServer.getSncpServer().addSncpServlet(wrapper);
|
||||
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
|
||||
}
|
||||
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
|
||||
@@ -268,7 +272,6 @@ public abstract class NodeServer {
|
||||
if (Modifier.isAbstract(type.getModifiers())) continue; //修饰abstract的类跳过
|
||||
if (DataSource.class.isAssignableFrom(type)) continue;
|
||||
if (CacheSource.class.isAssignableFrom(type)) continue;
|
||||
if (DataSQLListener.class.isAssignableFrom(type)) continue;
|
||||
if (DataCacheListener.class.isAssignableFrom(type)) continue;
|
||||
if (WebSocketNode.class.isAssignableFrom(type)) continue;
|
||||
}
|
||||
@@ -353,15 +356,22 @@ public abstract class NodeServer {
|
||||
localServiceWrappers.clear();
|
||||
localServiceWrappers.addAll(swlist);
|
||||
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
|
||||
CountDownLatch clds = new CountDownLatch(localServiceWrappers.size());
|
||||
localServiceWrappers.parallelStream().forEach(y -> {
|
||||
try {
|
||||
long s = System.currentTimeMillis();
|
||||
y.getService().init(y.getConf());
|
||||
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());
|
||||
} finally {
|
||||
clds.countDown();
|
||||
}
|
||||
});
|
||||
Collections.sort(slist);
|
||||
clds.await();
|
||||
if (slist != null && sb != null) {
|
||||
for (String s : slist) {
|
||||
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
|
||||
Collections.sort(wlist);
|
||||
for (String s : wlist) {
|
||||
sb.append(s);
|
||||
}
|
||||
}
|
||||
@@ -391,8 +401,9 @@ public abstract class NodeServer {
|
||||
Set<InetSocketAddress> addrs = new HashSet();
|
||||
transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses())));
|
||||
Transport first = transports.get(0);
|
||||
Transport newTransport = new Transport(groupid, application.findGroupProtocol(first.getName()), application.getWatchFactory(),
|
||||
application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
|
||||
GroupInfo ginfo = application.findGroupInfo(first.getName());
|
||||
Transport newTransport = new Transport(groupid, ginfo.getProtocol(), application.getWatchFactory(),
|
||||
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
|
||||
synchronized (application.resourceFactory) {
|
||||
transport = application.resourceFactory.find(groupid, Transport.class);
|
||||
if (transport == null) {
|
||||
@@ -414,10 +425,11 @@ public abstract class NodeServer {
|
||||
}
|
||||
return transport;
|
||||
}
|
||||
Set<InetSocketAddress> addrs = application.findGlobalGroup(group);
|
||||
GroupInfo ginfo = application.findGroupInfo(group);
|
||||
Set<InetSocketAddress> addrs = ginfo.copyAddrs();
|
||||
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
|
||||
transport = new Transport(group, application.findGroupProtocol(group), application.getWatchFactory(),
|
||||
application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
|
||||
transport = new Transport(group, ginfo.getProtocol(), application.getWatchFactory(),
|
||||
ginfo.getKind(), application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
|
||||
application.resourceFactory.register(group, transport);
|
||||
}
|
||||
return transport;
|
||||
|
||||
@@ -20,14 +20,22 @@ import org.redkale.util.*;
|
||||
* @author zhangjx
|
||||
*/
|
||||
@NodeProtocol({"SNCP"})
|
||||
public final class NodeSncpServer extends NodeServer {
|
||||
public class NodeSncpServer extends NodeServer {
|
||||
|
||||
private final SncpServer sncpServer;
|
||||
protected final SncpServer sncpServer;
|
||||
|
||||
public NodeSncpServer(Application application, AnyValue serconf) {
|
||||
private NodeSncpServer(Application application, AnyValue serconf) {
|
||||
super(application, createServer(application, serconf));
|
||||
this.sncpServer = (SncpServer) this.server;
|
||||
this.consumer = sncpServer == null ? null : x -> sncpServer.addService(x);
|
||||
this.consumer = sncpServer == null ? null : x -> sncpServer.addSncpServlet(x);
|
||||
}
|
||||
|
||||
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
||||
if (serconf != null && serconf.getAnyValue("rest") != null) {
|
||||
((AnyValue.DefaultAnyValue) serconf).addValue("_$sncp", "true");
|
||||
return new NodeHttpServer(application, serconf);
|
||||
}
|
||||
return new NodeSncpServer(application, serconf);
|
||||
}
|
||||
|
||||
private static Server createServer(Application application, AnyValue serconf) {
|
||||
|
||||
85
src/org/redkale/boot/apidoc-template.html
Normal file
85
src/org/redkale/boot/apidoc-template.html
Normal file
@@ -0,0 +1,85 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"><title>Document</title>
|
||||
<style type="text/css">
|
||||
body {text-align: center;margin:auto;}
|
||||
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 td,.table th{padding: 0.4rem 1.2rem 0.4rem 1.2rem;border: 1px solid #aaa;}
|
||||
.table td {text-align: left;}
|
||||
.s {font-size: 0.8rem; vertical-align: middle;}
|
||||
.subtable {border-spacing: 0;border: 0;margin:0;}
|
||||
.subtable td{border: 0;padding: 0 0 0 10px;}
|
||||
.typetable {border-spacing: 0;border: 0;margin:0;}
|
||||
.typetable td{border: 0;padding: 2px 20px 2px 10px;}
|
||||
.typetable .l{border-bottom: 1px solid red;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
var createhtml = function (jsoncontent) {
|
||||
var classmap = jsoncontent.types;
|
||||
var html = [];
|
||||
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">');
|
||||
for (var i = 0; i < jsoncontent.servers.length; i++) {
|
||||
for (var j = 0; j < jsoncontent.servers[i].servlets.length; j++) {
|
||||
var servlet = jsoncontent.servers[i].servlets[j];
|
||||
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
||||
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
|
||||
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
|
||||
for (var k = 0; k < servlet.actions.length; k++) {
|
||||
var action = servlet.actions[k];
|
||||
html.push(' <tr>');
|
||||
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
|
||||
html.push('<td>' + action.comment + '</td>');
|
||||
html.push('<td class="s">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
|
||||
var paramshtml = [];
|
||||
paramshtml.push('<table class="subtable">');
|
||||
for (var p = 0; p < action.params.length; p++) {
|
||||
var param = action.params[p];
|
||||
var t = param.type.substring(param.type.lastIndexOf('.') + 1);
|
||||
if (classmap[param.type.replace('[]', '')]) {
|
||||
t = '<a href="#' + param.type.replace('[]', '') + '">' + t + '</a>';
|
||||
}
|
||||
if (param.name == '&') {
|
||||
paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>');
|
||||
} else {
|
||||
var c = ' style="font-weight:bold;"';
|
||||
if (param.src == "HEADER") c = ' style="color:red;font-weight:bold;"';
|
||||
if (param.src == "COOKIE") c = ' style="color:blue;font-weight:bold;"';
|
||||
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
|
||||
}
|
||||
}
|
||||
paramshtml.push('</table>');
|
||||
html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>');
|
||||
html.push('<td>' + action.result.replace(/</g,"<").replace(/>/g,">").replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</td>');
|
||||
html.push('</tr>');
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var type in classmap) {
|
||||
html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
||||
html.push(' <tr id="' + type + '"><th colspan="5" style="border-top:0;">' + type + '</th></tr>');
|
||||
html.push(' <tr><td colspan="5"><table class="typetable">');
|
||||
for (var fieldname in classmap[type]) {
|
||||
var field = classmap[type][fieldname];
|
||||
var t = field.type.replace(/</g,"<").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>');
|
||||
}
|
||||
html.push(' </table></td></tr>');
|
||||
}
|
||||
html.push('</table><br/><br/><br/>');
|
||||
html.push('</div>');
|
||||
return html.join('');
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var jsoncontent = ${content};
|
||||
document.write(createhtml(jsoncontent));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* 提供RedKale服务器的启动、初始化和加载功能
|
||||
* 提供Redkale服务器的启动、初始化和加载功能
|
||||
*/
|
||||
package org.redkale.boot;
|
||||
|
||||
@@ -104,6 +104,14 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
this.register(double[].class, DoubleArraySimpledCoder.instance);
|
||||
this.register(String[].class, StringArraySimpledCoder.instance);
|
||||
//---------------------------------------------------------
|
||||
this.register(HttpCookie.class, new Creator<HttpCookie>() {
|
||||
@Override
|
||||
@Creator.ConstructorParameters({"name", "value"})
|
||||
public HttpCookie create(Object... params) {
|
||||
return new HttpCookie((String) params[0], (String) params[1]);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +212,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
/**
|
||||
* 使所有类的所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false
|
||||
*
|
||||
* @param skipIgnore
|
||||
* @param skipIgnore 忽略ignore
|
||||
*
|
||||
* @return 自身
|
||||
*/
|
||||
@@ -387,7 +395,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
} else if (clazz == Object.class) {
|
||||
od = new ObjectDecoder(type);
|
||||
decoder = od;
|
||||
} else if (!clazz.getName().startsWith("java.") || clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
||||
} else if (!clazz.getName().startsWith("java.")
|
||||
|| java.net.HttpCookie.class == clazz
|
||||
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
|
||||
Decodeable simpleCoder = null;
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
if (!Modifier.isStatic(method.getModifiers())) continue;
|
||||
@@ -467,7 +477,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
encoder = new MapEncoder(this, type);
|
||||
} else if (clazz == Object.class) {
|
||||
return (Encodeable<W, E>) this.anyEncoder;
|
||||
} else if (!clazz.getName().startsWith("java.")) {
|
||||
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz) {
|
||||
Encodeable simpleCoder = null;
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
if (!Modifier.isStatic(method.getModifiers())) continue;
|
||||
|
||||
@@ -121,7 +121,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value != null && value.getClass() != this.typeClass) {
|
||||
if (value.getClass() != this.typeClass) {
|
||||
final Class clz = value.getClass();
|
||||
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clz));
|
||||
factory.loadEncoder(clz).convertTo(out, value);
|
||||
|
||||
@@ -91,4 +91,8 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
||||
protected void setServletConf(Servlet servlet, AnyValue conf) {
|
||||
servlet._conf = conf;
|
||||
}
|
||||
|
||||
public Set<S> getServlets() {
|
||||
return new LinkedHashSet<>(servlets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ public final class Transport {
|
||||
|
||||
protected final String name; //即<group>的name属性
|
||||
|
||||
protected final String kind; //即<group>的kind属性
|
||||
|
||||
protected final boolean tcp;
|
||||
|
||||
protected final String protocol;
|
||||
@@ -60,15 +62,16 @@ public final class Transport {
|
||||
|
||||
protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>();
|
||||
|
||||
public Transport(String name, WatchFactory watch, final ObjectPool<ByteBuffer> transportBufferPool,
|
||||
public Transport(String name, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool,
|
||||
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
|
||||
this(name, DEFAULT_PROTOCOL, watch, transportBufferPool, transportChannelGroup, clientAddress, addresses);
|
||||
this(name, DEFAULT_PROTOCOL, watch, kind, transportBufferPool, transportChannelGroup, clientAddress, addresses);
|
||||
}
|
||||
|
||||
public Transport(String name, String protocol, WatchFactory watch, final ObjectPool<ByteBuffer> transportBufferPool,
|
||||
public Transport(String name, String protocol, WatchFactory watch, String kind, final ObjectPool<ByteBuffer> transportBufferPool,
|
||||
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
|
||||
this.name = name;
|
||||
this.watch = watch;
|
||||
this.kind = kind == null ? "" : kind.trim();
|
||||
this.protocol = protocol;
|
||||
this.tcp = "TCP".equalsIgnoreCase(protocol);
|
||||
this.group = transportChannelGroup;
|
||||
@@ -87,6 +90,7 @@ public final class Transport {
|
||||
//必须按字母排列顺序确保,相同内容的transport列表组合的name相同,而不会因为list的顺序不同产生不同的name
|
||||
this.name = tmpgroup.stream().sorted().collect(Collectors.joining(";"));
|
||||
this.watch = first.watch;
|
||||
this.kind = first.kind;
|
||||
this.protocol = first.protocol;
|
||||
this.tcp = "TCP".equalsIgnoreCase(first.protocol);
|
||||
this.group = first.group;
|
||||
@@ -114,6 +118,10 @@ public final class Transport {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
connPool.forEach((k, v) -> v.forEach(c -> c.dispose()));
|
||||
}
|
||||
|
||||
@@ -5,345 +5,14 @@
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import org.redkale.net.Response;
|
||||
import org.redkale.net.Request;
|
||||
import org.redkale.util.AnyValue;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import org.redkale.service.RetResult;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @deprecated 使用 org.redkale.net.http.HttpBaseServlet 代替
|
||||
* @see org.redkale.net.http.HttpBaseServlet
|
||||
* @author zhangjx
|
||||
*/
|
||||
public abstract class BasedHttpServlet extends HttpServlet {
|
||||
|
||||
public static final int RET_METHOD_ERROR = 1800_0001;
|
||||
|
||||
/**
|
||||
* 配合 BasedHttpServlet 使用。
|
||||
* 当标记为 @AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({METHOD, TYPE})
|
||||
@Retention(RUNTIME)
|
||||
protected @interface AuthIgnore {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 配合 BasedHttpServlet 使用。
|
||||
* 用于对@WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀, 且不能是正则表达式
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
protected @interface WebAction {
|
||||
|
||||
int actionid() default 0;
|
||||
|
||||
String url();
|
||||
|
||||
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法
|
||||
}
|
||||
|
||||
/**
|
||||
* 配合 BasedHttpServlet 使用。
|
||||
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一定时间(默认值timeout=15秒)。
|
||||
* 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,因为没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
protected @interface HttpCacheable {
|
||||
|
||||
/**
|
||||
* 超时的秒数
|
||||
*
|
||||
* @return 超时秒数
|
||||
*/
|
||||
int timeout() default 15;
|
||||
}
|
||||
|
||||
private Map.Entry<String, Entry>[] actions;
|
||||
|
||||
public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
|
||||
if (!preExecute(request, response)) return;
|
||||
for (Map.Entry<String, Entry> en : actions) {
|
||||
if (request.getRequestURI().startsWith(en.getKey())) {
|
||||
Entry entry = en.getValue();
|
||||
if (!entry.checkMethod(request.getMethod())) {
|
||||
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
|
||||
return;
|
||||
}
|
||||
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
|
||||
if (entry.cachetimeout > 0) {//有缓存设置
|
||||
CacheEntry ce = entry.cache.get(request.getRequestURI());
|
||||
if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效
|
||||
response.setStatus(ce.status);
|
||||
response.setContentType(ce.contentType);
|
||||
response.finish(ce.getBuffers());
|
||||
return;
|
||||
}
|
||||
response.setBufferHandler(entry.cacheHandler);
|
||||
}
|
||||
entry.servlet.execute(request, response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
|
||||
}
|
||||
|
||||
public final void preInit(HttpContext context, AnyValue config) {
|
||||
String path = _prefix == null ? "" : _prefix;
|
||||
WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
|
||||
if (ws != null && !ws.repair()) path = "";
|
||||
HashMap<String, Entry> map = load();
|
||||
this.actions = new Map.Entry[map.size()];
|
||||
int i = -1;
|
||||
for (Map.Entry<String, Entry> en : map.entrySet()) {
|
||||
actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
|
||||
}
|
||||
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
|
||||
Arrays.sort(actions, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
|
||||
}
|
||||
|
||||
public final void postDestroy(HttpContext context, AnyValue config) {
|
||||
}
|
||||
|
||||
public abstract boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException;
|
||||
|
||||
private HashMap<String, Entry> load() {
|
||||
final boolean typeIgnore = this.getClass().getAnnotation(AuthIgnore.class) != null;
|
||||
WebServlet module = this.getClass().getAnnotation(WebServlet.class);
|
||||
final int serviceid = module == null ? 0 : module.moduleid();
|
||||
final HashMap<String, Entry> map = new HashMap<>();
|
||||
Set<String> nameset = new HashSet<>();
|
||||
for (final Method method : this.getClass().getMethods()) {
|
||||
//-----------------------------------------------
|
||||
String methodname = method.getName();
|
||||
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
|
||||
//-----------------------------------------------
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
|
||||
|| paramTypes[1] != HttpResponse.class) continue;
|
||||
//-----------------------------------------------
|
||||
Class[] exps = method.getExceptionTypes();
|
||||
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
|
||||
//-----------------------------------------------
|
||||
|
||||
final WebAction action = method.getAnnotation(WebAction.class);
|
||||
if (action == null) continue;
|
||||
final int actionid = action.actionid();
|
||||
final String name = action.url().trim();
|
||||
|
||||
if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")");
|
||||
//屏蔽以下代码,允许相互包含
|
||||
// for (String n : nameset) {
|
||||
// if (n.contains(name) || name.contains(n)) {
|
||||
// throw new RuntimeException(this.getClass().getSimpleName() + " has two sub-contains " + WebAction.class.getSimpleName() + "(" + name + ", " + n + ")");
|
||||
// }
|
||||
// }
|
||||
nameset.add(name);
|
||||
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method)));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private HttpServlet createHttpServlet(final Method method) {
|
||||
//------------------------------------------------------------------------------
|
||||
final String supDynName = HttpServlet.class.getName().replace('.', '/');
|
||||
final String interName = this.getClass().getName().replace('.', '/');
|
||||
final String interDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(this.getClass());
|
||||
final String requestSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Request.class);
|
||||
final String responseSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Response.class);
|
||||
final String requestDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpRequest.class);
|
||||
final String responseDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpResponse.class);
|
||||
String newDynName = interName + "_Dyn_" + method.getName();
|
||||
int i = 0;
|
||||
for (;;) {
|
||||
try {
|
||||
Class.forName(newDynName.replace('/', '.'));
|
||||
newDynName += "_" + (++i);
|
||||
} catch (Exception ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
MethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
final String factfield = "_factServlet";
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
|
||||
{
|
||||
fv = cw.visitField(ACC_PUBLIC, factfield, interDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ //构造函数
|
||||
mv = (cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||||
//mv.setDebug(true);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = (cw.visitMethod(ACC_PUBLIC, "execute", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/io/IOException"}));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, factfield, interDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, interName, method.getName(), "(" + requestDesc + responseDesc + ")V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "execute", "(" + requestSupDesc + responseSupDesc + ")V", null, new String[]{"java/io/IOException"});
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitTypeInsn(CHECKCAST, HttpRequest.class.getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitTypeInsn(CHECKCAST, HttpResponse.class.getName().replace('.', '/'));
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "execute", "(" + requestDesc + responseDesc + ")V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
//------------------------------------------------------------------------------
|
||||
byte[] bytes = cw.toByteArray();
|
||||
Class<?> newClazz = new ClassLoader(this.getClass().getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
try {
|
||||
HttpServlet instance = (HttpServlet) newClazz.newInstance();
|
||||
instance.getClass().getField(factfield).set(instance, this);
|
||||
return instance;
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Entry {
|
||||
|
||||
public Entry(boolean typeIgnore, int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) {
|
||||
this.moduleid = moduleid;
|
||||
this.actionid = actionid;
|
||||
this.name = name;
|
||||
this.methods = methods;
|
||||
this.method = method;
|
||||
this.servlet = servlet;
|
||||
this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null;
|
||||
HttpCacheable hc = method.getAnnotation(HttpCacheable.class);
|
||||
this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000;
|
||||
this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null;
|
||||
this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
|
||||
int status = response.getStatus();
|
||||
if (status != 200) return null;
|
||||
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
|
||||
cache.put(response.getRequest().getRequestURI(), ce);
|
||||
return ce.getBuffers();
|
||||
} : null;
|
||||
}
|
||||
|
||||
public boolean isNeedCheck() {
|
||||
return this.moduleid != 0 || this.actionid != 0;
|
||||
}
|
||||
|
||||
public boolean checkMethod(final String reqMethod) {
|
||||
if (methods.length == 0) return true;
|
||||
for (String m : methods) {
|
||||
if (reqMethod.equalsIgnoreCase(m)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final HttpResponse.BufferHandler cacheHandler;
|
||||
|
||||
public final ConcurrentHashMap<String, CacheEntry> cache;
|
||||
|
||||
public final int cachetimeout;
|
||||
|
||||
public final boolean ignore;
|
||||
|
||||
public final int moduleid;
|
||||
|
||||
public final int actionid;
|
||||
|
||||
public final String name;
|
||||
|
||||
public final String[] methods;
|
||||
|
||||
public final Method method;
|
||||
|
||||
public final HttpServlet servlet;
|
||||
}
|
||||
|
||||
private static final class CacheEntry {
|
||||
|
||||
public final long time = System.currentTimeMillis();
|
||||
|
||||
private final ByteBuffer[] buffers;
|
||||
|
||||
private final int status;
|
||||
|
||||
private final String contentType;
|
||||
|
||||
public CacheEntry(int status, String contentType, ByteBuffer[] bufs) {
|
||||
this.status = status;
|
||||
this.contentType = contentType;
|
||||
final ByteBuffer[] newBuffers = new ByteBuffer[bufs.length];
|
||||
for (int i = 0; i < newBuffers.length; i++) {
|
||||
newBuffers[i] = bufs[i].duplicate().asReadOnlyBuffer();
|
||||
}
|
||||
this.buffers = newBuffers;
|
||||
}
|
||||
|
||||
public ByteBuffer[] getBuffers() {
|
||||
final ByteBuffer[] newBuffers = new ByteBuffer[buffers.length];
|
||||
for (int i = 0; i < newBuffers.length; i++) {
|
||||
newBuffers[i] = buffers[i].duplicate();
|
||||
}
|
||||
return newBuffers;
|
||||
}
|
||||
}
|
||||
public abstract class BasedHttpServlet extends HttpBaseServlet {
|
||||
}
|
||||
29
src/org/redkale/net/http/DefaultRestServlet.java
Normal file
29
src/org/redkale/net/http/DefaultRestServlet.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 默认Servlet, 没有配置RestHttpServlet实现类则使用该默认类
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class DefaultRestServlet extends RestHttpServlet<Object> {
|
||||
|
||||
@Override
|
||||
protected Object currentUser(HttpRequest req) throws IOException {
|
||||
return new Object();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
408
src/org/redkale/net/http/HttpBaseServlet.java
Normal file
408
src/org/redkale/net/http/HttpBaseServlet.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import org.redkale.net.Response;
|
||||
import org.redkale.net.Request;
|
||||
import org.redkale.util.AnyValue;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import org.redkale.service.RetResult;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public abstract class HttpBaseServlet extends HttpServlet {
|
||||
|
||||
public static final int RET_SERVER_ERROR = 1800_0001;
|
||||
|
||||
public static final int RET_METHOD_ERROR = 1800_0002;
|
||||
|
||||
/**
|
||||
* 配合 HttpBaseServlet 使用。
|
||||
* 当标记为 @AuthIgnore 的方法在执行execute之前不会调用authenticate 方法。
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({METHOD, TYPE})
|
||||
@Retention(RUNTIME)
|
||||
protected @interface AuthIgnore {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 配合 @WebParam 使用。
|
||||
* 用于对@WebParam中参数的来源类型
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
protected enum ParamSourceType {
|
||||
|
||||
PARAMETER, HEADER, COOKIE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配合 @WebAction 使用。
|
||||
* 用于对@WebAction方法中参数描述
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD})
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(WebParams.class)
|
||||
protected @interface WebParam {
|
||||
|
||||
String name(); //参数名
|
||||
|
||||
Class type(); //参数的数据类型
|
||||
|
||||
String comment() default ""; //备注描述
|
||||
|
||||
ParamSourceType src() default ParamSourceType.PARAMETER; //参数来源类型
|
||||
|
||||
int radix() default 10; //转换数字byte/short/int/long时所用的进制数, 默认10进制
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Target({METHOD})
|
||||
@Retention(RUNTIME)
|
||||
protected @interface WebParams {
|
||||
|
||||
WebParam[] value();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配合 HttpBaseServlet 使用。
|
||||
* 用于对@WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀, 且不能是正则表达式
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD})
|
||||
@Retention(RUNTIME)
|
||||
protected @interface WebAction {
|
||||
|
||||
int actionid() default 0;
|
||||
|
||||
String url();
|
||||
|
||||
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法
|
||||
|
||||
String comment() default ""; //备注描述
|
||||
|
||||
String result() default "Object"; //输出结果的数据类型
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 配合 HttpBaseServlet 使用。
|
||||
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值timeout=15秒)。
|
||||
* 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD})
|
||||
@Retention(RUNTIME)
|
||||
protected @interface HttpCacheable {
|
||||
|
||||
/**
|
||||
* 超时的秒数
|
||||
*
|
||||
* @return 超时秒数
|
||||
*/
|
||||
int timeout() default 15;
|
||||
}
|
||||
|
||||
private Map.Entry<String, Entry>[] actions;
|
||||
|
||||
public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
|
||||
if (!preExecute(request, response)) return;
|
||||
for (Map.Entry<String, Entry> en : actions) {
|
||||
if (request.getRequestURI().startsWith(en.getKey())) {
|
||||
Entry entry = en.getValue();
|
||||
if (!entry.checkMethod(request.getMethod())) {
|
||||
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
|
||||
return;
|
||||
}
|
||||
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
|
||||
if (entry.cachetimeout > 0) {//有缓存设置
|
||||
CacheEntry ce = entry.cache.get(request.getRequestURI());
|
||||
if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效
|
||||
response.setStatus(ce.status);
|
||||
response.setContentType(ce.contentType);
|
||||
response.finish(ce.getBuffers());
|
||||
return;
|
||||
}
|
||||
response.setBufferHandler(entry.cacheHandler);
|
||||
}
|
||||
entry.servlet.execute(request, response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
|
||||
}
|
||||
|
||||
public final void preInit(HttpContext context, AnyValue config) {
|
||||
String path = _prefix == null ? "" : _prefix;
|
||||
WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
|
||||
if (ws != null && !ws.repair()) path = "";
|
||||
HashMap<String, Entry> map = load();
|
||||
this.actions = new Map.Entry[map.size()];
|
||||
int i = -1;
|
||||
for (Map.Entry<String, Entry> en : map.entrySet()) {
|
||||
actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
|
||||
}
|
||||
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
|
||||
Arrays.sort(actions, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
|
||||
}
|
||||
|
||||
public final void postDestroy(HttpContext context, AnyValue config) {
|
||||
}
|
||||
|
||||
public abstract boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException;
|
||||
|
||||
protected String _prefix(HttpServlet servlet) {
|
||||
return servlet._prefix;
|
||||
}
|
||||
|
||||
private HashMap<String, Entry> load() {
|
||||
final boolean typeIgnore = this.getClass().getAnnotation(AuthIgnore.class) != null;
|
||||
WebServlet module = this.getClass().getAnnotation(WebServlet.class);
|
||||
final int serviceid = module == null ? 0 : module.moduleid();
|
||||
final HashMap<String, Entry> map = new HashMap<>();
|
||||
Set<String> nameset = new HashSet<>();
|
||||
for (final Method method : this.getClass().getMethods()) {
|
||||
//-----------------------------------------------
|
||||
String methodname = method.getName();
|
||||
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
|
||||
//-----------------------------------------------
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
|
||||
|| paramTypes[1] != HttpResponse.class) continue;
|
||||
//-----------------------------------------------
|
||||
Class[] exps = method.getExceptionTypes();
|
||||
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
|
||||
//-----------------------------------------------
|
||||
|
||||
final WebAction action = method.getAnnotation(WebAction.class);
|
||||
if (action == null) continue;
|
||||
final int actionid = action.actionid();
|
||||
final String name = action.url().trim();
|
||||
|
||||
if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")");
|
||||
//屏蔽以下代码,允许相互包含
|
||||
// for (String n : nameset) {
|
||||
// if (n.contains(name) || name.contains(n)) {
|
||||
// throw new RuntimeException(this.getClass().getSimpleName() + " has two sub-contains " + WebAction.class.getSimpleName() + "(" + name + ", " + n + ")");
|
||||
// }
|
||||
// }
|
||||
nameset.add(name);
|
||||
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method)));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private HttpServlet createHttpServlet(final Method method) {
|
||||
//------------------------------------------------------------------------------
|
||||
final String supDynName = HttpServlet.class.getName().replace('.', '/');
|
||||
final String interName = this.getClass().getName().replace('.', '/');
|
||||
final String interDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(this.getClass());
|
||||
final String requestSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Request.class);
|
||||
final String responseSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Response.class);
|
||||
final String requestDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpRequest.class);
|
||||
final String responseDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpResponse.class);
|
||||
String newDynName = interName + "_Dyn_" + method.getName();
|
||||
int i = 0;
|
||||
for (;;) {
|
||||
try {
|
||||
Class.forName(newDynName.replace('/', '.'));
|
||||
newDynName += "_" + (++i);
|
||||
} catch (Exception ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
MethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
final String factfield = "_factServlet";
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
|
||||
{
|
||||
fv = cw.visitField(ACC_PUBLIC, factfield, interDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ //构造函数
|
||||
mv = (cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||||
//mv.setDebug(true);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = (cw.visitMethod(ACC_PUBLIC, "execute", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/io/IOException"}));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, factfield, interDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, interName, method.getName(), "(" + requestDesc + responseDesc + ")V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "execute", "(" + requestSupDesc + responseSupDesc + ")V", null, new String[]{"java/io/IOException"});
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitTypeInsn(CHECKCAST, HttpRequest.class.getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitTypeInsn(CHECKCAST, HttpResponse.class.getName().replace('.', '/'));
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "execute", "(" + requestDesc + responseDesc + ")V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
//------------------------------------------------------------------------------
|
||||
byte[] bytes = cw.toByteArray();
|
||||
Class<?> newClazz = new ClassLoader(this.getClass().getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
try {
|
||||
HttpServlet instance = (HttpServlet) newClazz.newInstance();
|
||||
instance.getClass().getField(factfield).set(instance, this);
|
||||
return instance;
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Entry {
|
||||
|
||||
public Entry(boolean typeIgnore, int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) {
|
||||
this.moduleid = moduleid;
|
||||
this.actionid = actionid;
|
||||
this.name = name;
|
||||
this.methods = methods;
|
||||
this.method = method;
|
||||
this.servlet = servlet;
|
||||
this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null;
|
||||
HttpCacheable hc = method.getAnnotation(HttpCacheable.class);
|
||||
this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000;
|
||||
this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null;
|
||||
this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
|
||||
int status = response.getStatus();
|
||||
if (status != 200) return null;
|
||||
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
|
||||
cache.put(response.getRequest().getRequestURI(), ce);
|
||||
return ce.getBuffers();
|
||||
} : null;
|
||||
}
|
||||
|
||||
public boolean isNeedCheck() {
|
||||
return this.moduleid != 0 || this.actionid != 0;
|
||||
}
|
||||
|
||||
public boolean checkMethod(final String reqMethod) {
|
||||
if (methods.length == 0) return true;
|
||||
for (String m : methods) {
|
||||
if (reqMethod.equalsIgnoreCase(m)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final HttpResponse.BufferHandler cacheHandler;
|
||||
|
||||
public final ConcurrentHashMap<String, CacheEntry> cache;
|
||||
|
||||
public final int cachetimeout;
|
||||
|
||||
public final boolean ignore;
|
||||
|
||||
public final int moduleid;
|
||||
|
||||
public final int actionid;
|
||||
|
||||
public final String name;
|
||||
|
||||
public final String[] methods;
|
||||
|
||||
public final Method method;
|
||||
|
||||
public final HttpServlet servlet;
|
||||
}
|
||||
|
||||
private static final class CacheEntry {
|
||||
|
||||
public final long time = System.currentTimeMillis();
|
||||
|
||||
private final ByteBuffer[] buffers;
|
||||
|
||||
private final int status;
|
||||
|
||||
private final String contentType;
|
||||
|
||||
public CacheEntry(int status, String contentType, ByteBuffer[] bufs) {
|
||||
this.status = status;
|
||||
this.contentType = contentType;
|
||||
final ByteBuffer[] newBuffers = new ByteBuffer[bufs.length];
|
||||
for (int i = 0; i < newBuffers.length; i++) {
|
||||
newBuffers[i] = bufs[i].duplicate().asReadOnlyBuffer();
|
||||
}
|
||||
this.buffers = newBuffers;
|
||||
}
|
||||
|
||||
public ByteBuffer[] getBuffers() {
|
||||
final ByteBuffer[] newBuffers = new ByteBuffer[buffers.length];
|
||||
for (int i = 0; i < newBuffers.length; i++) {
|
||||
newBuffers[i] = buffers[i].duplicate();
|
||||
}
|
||||
return newBuffers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,21 +23,23 @@ import org.redkale.watch.*;
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext, HttpRequest, HttpResponse, HttpServlet> {
|
||||
public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, HttpRequest, HttpResponse, HttpServlet> {
|
||||
|
||||
private SimpleEntry<Predicate<String>, HttpServlet>[] regArray = new SimpleEntry[0];
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
private HttpServlet resourceHttpServlet = new HttpResourceServlet();
|
||||
protected SimpleEntry<Predicate<String>, HttpServlet>[] regArray = new SimpleEntry[0];
|
||||
|
||||
private final Map<String, Class> mapStrings = new HashMap<>();
|
||||
protected HttpServlet resourceHttpServlet = new HttpResourceServlet();
|
||||
|
||||
protected final Map<String, Class> allMapStrings = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void init(HttpContext context, AnyValue config) {
|
||||
this.servlets.forEach(s -> {
|
||||
if (s instanceof WebSocketServlet) {
|
||||
((WebSocketServlet) s).preInit(context, getServletConf(s));
|
||||
} else if (s instanceof BasedHttpServlet) {
|
||||
((BasedHttpServlet) s).preInit(context, getServletConf(s));
|
||||
} else if (s instanceof HttpBaseServlet) {
|
||||
((HttpBaseServlet) s).preInit(context, getServletConf(s));
|
||||
}
|
||||
s.init(context, getServletConf(s));
|
||||
});
|
||||
@@ -47,17 +49,11 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
|
||||
watch.inject(s);
|
||||
});
|
||||
}
|
||||
if (config != null) {
|
||||
AnyValue ssConfig = config.getAnyValue("servlets");
|
||||
AnyValue resConfig = null;
|
||||
if (ssConfig != null) {
|
||||
resConfig = ssConfig.getAnyValue("resource-servlet");
|
||||
if ((resConfig instanceof DefaultAnyValue) && resConfig.getValue("webroot") == null) {
|
||||
AnyValue resConfig = config.getAnyValue("resource-servlet");
|
||||
if ((resConfig instanceof DefaultAnyValue) && resConfig.getValue("webroot", "").isEmpty()) {
|
||||
((DefaultAnyValue) resConfig).addValue("webroot", config.getValue("root"));
|
||||
}
|
||||
}
|
||||
if (resConfig == null) resConfig = config.getAnyValue("resource-servlet"); //兼容
|
||||
if (resConfig == null) {
|
||||
if (resConfig == null) { //主要用于嵌入式的HttpServer初始化
|
||||
DefaultAnyValue dresConfig = new DefaultAnyValue();
|
||||
dresConfig.addValue("webroot", config.getValue("root"));
|
||||
dresConfig.addValue("ranges", config.getValue("ranges"));
|
||||
@@ -70,8 +66,14 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
|
||||
}
|
||||
resConfig = dresConfig;
|
||||
}
|
||||
this.resourceHttpServlet.init(context, resConfig);
|
||||
String resServlet = resConfig.getValue("servlet", HttpResourceServlet.class.getName());
|
||||
try {
|
||||
this.resourceHttpServlet = (HttpServlet) Class.forName(resServlet).newInstance();
|
||||
} catch (Exception e) {
|
||||
this.resourceHttpServlet = new HttpResourceServlet();
|
||||
logger.log(Level.WARNING, "init HttpResourceSerlvet(" + resServlet + ") error", e);
|
||||
}
|
||||
this.resourceHttpServlet.init(context, resConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,17 +104,14 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
|
||||
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
|
||||
if (ws != null) {
|
||||
mappings = ws.value();
|
||||
if (!ws.repair()) prefix = "";//被设置为自动追加前缀则清空prefix
|
||||
if (!ws.repair()) prefix = "";//被设置为不自动追加前缀则清空prefix
|
||||
}
|
||||
}
|
||||
synchronized (mapStrings) {
|
||||
synchronized (allMapStrings) {
|
||||
for (String mapping : mappings) {
|
||||
if (mapping == null) continue;
|
||||
if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
|
||||
if (this.mapStrings.containsKey(mapping)) {
|
||||
Class old = this.mapStrings.get(mapping);
|
||||
throw new RuntimeException("mapping [" + mapping + "] repeat on " + old.getName() + " and " + servlet.getClass().getName());
|
||||
}
|
||||
|
||||
if (contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
|
||||
if (mapping.charAt(0) != '^') mapping = '^' + mapping;
|
||||
if (mapping.endsWith("/*")) {
|
||||
@@ -130,7 +129,11 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
|
||||
} else if (mapping != null && !mapping.isEmpty()) {
|
||||
super.mappings.put(mapping, servlet);
|
||||
}
|
||||
this.mapStrings.put(mapping, servlet.getClass());
|
||||
if (this.allMapStrings.containsKey(mapping)) {
|
||||
Class old = this.allMapStrings.get(mapping);
|
||||
throw new RuntimeException("mapping [" + mapping + "] repeat on " + old.getName() + " and " + servlet.getClass().getName());
|
||||
}
|
||||
this.allMapStrings.put(mapping, servlet.getClass());
|
||||
}
|
||||
setServletConf(servlet, conf);
|
||||
servlet._prefix = prefix.toString();
|
||||
@@ -165,11 +168,11 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
|
||||
s.destroy(context, getServletConf(s));
|
||||
if (s instanceof WebSocketServlet) {
|
||||
((WebSocketServlet) s).postDestroy(context, getServletConf(s));
|
||||
} else if (s instanceof BasedHttpServlet) {
|
||||
((BasedHttpServlet) s).postDestroy(context, getServletConf(s));
|
||||
} else if (s instanceof HttpBaseServlet) {
|
||||
((HttpBaseServlet) s).postDestroy(context, getServletConf(s));
|
||||
}
|
||||
});
|
||||
this.mapStrings.clear();
|
||||
this.allMapStrings.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ import org.redkale.util.ByteArray;
|
||||
|
||||
/**
|
||||
* Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。 <br>
|
||||
* 同时提供json的解析接口: public Object getJsonParameter(Class clazz, String name) <br>
|
||||
* RedKale提倡带简单的参数的GET请求采用类似REST风格, 因此提供了 getRequstURIPath 系列接口。 <br>
|
||||
* 同时提供json的解析接口: public Object getJsonParameter(Type type, String name) <br>
|
||||
* Redkale提倡带简单的参数的GET请求采用类似REST风格, 因此提供了 getRequstURIPath 系列接口。 <br>
|
||||
* 例如简单的翻页查询 <br>
|
||||
* /pipes/record/query/offset:0/limit:20 <br>
|
||||
* 获取页号: int offset = request.getRequstURIPath("offset:", 0); <br>
|
||||
@@ -312,6 +312,7 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
* 获取文件上传信息列表
|
||||
*
|
||||
* @return 文件上传对象集合
|
||||
*
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public final Iterable<MultiPart> multiParts() throws IOException {
|
||||
@@ -544,11 +545,27 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return val == null ? defvalue : Short.parseShort(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求URL分段中含prefix段的short值 <br>
|
||||
* 例如请求URL /pipes/record/query/type:a <br>
|
||||
* 获取type参数: short type = request.getRequstURIPath(16, "type:", (short)0); //type = 10
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param prefix prefix段前缀
|
||||
* @param defvalue 默认short值
|
||||
*
|
||||
* @return short值
|
||||
*/
|
||||
public short getRequstURIPath(int radix, String prefix, short defvalue) {
|
||||
String val = getRequstURIPath(prefix, null);
|
||||
return val == null ? defvalue : Short.parseShort(val, radix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求URL分段中含prefix段的int值 <br>
|
||||
* 例如请求URL /pipes/record/query/offset:0/limit:50 <br>
|
||||
* 获取起址参数: int offset = request.getRequstURIPath("offset:", 0); <br>
|
||||
* 获取行数参数: int limit = request.getRequstURIPath("limit:", 20); <br>
|
||||
* 获取offset参数: int offset = request.getRequstURIPath("offset:", 0); <br>
|
||||
* 获取limit参数: int limit = request.getRequstURIPath("limit:", 20); <br>
|
||||
*
|
||||
* @param prefix prefix段前缀
|
||||
* @param defvalue 默认int值
|
||||
@@ -560,6 +577,23 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return val == null ? defvalue : Integer.parseInt(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求URL分段中含prefix段的int值 <br>
|
||||
* 例如请求URL /pipes/record/query/offset:0/limit:50 <br>
|
||||
* 获取offset参数: int offset = request.getRequstURIPath("offset:", 0); <br>
|
||||
* 获取limit参数: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16 <br>
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param prefix prefix段前缀
|
||||
* @param defvalue 默认int值
|
||||
*
|
||||
* @return int值
|
||||
*/
|
||||
public int getRequstURIPath(int radix, String prefix, int defvalue) {
|
||||
String val = getRequstURIPath(prefix, null);
|
||||
return val == null ? defvalue : Integer.parseInt(val, radix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求URL分段中含prefix段的float值 <br>
|
||||
* 例如请求URL /pipes/record/query/point:40.0 <br>
|
||||
@@ -590,6 +624,22 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return val == null ? defvalue : Long.parseLong(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求URL分段中含prefix段的long值 <br>
|
||||
* 例如请求URL /pipes/record/query/time:1453104341363/id:40 <br>
|
||||
* 获取time参数: long time = request.getRequstURIPath(16, "time:", 0L);
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param prefix prefix段前缀
|
||||
* @param defvalue 默认long值
|
||||
*
|
||||
* @return long值
|
||||
*/
|
||||
public long getRequstURIPath(int radix, String prefix, long defvalue) {
|
||||
String val = getRequstURIPath(prefix, null);
|
||||
return val == null ? defvalue : Long.parseLong(val, radix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求URL分段中含prefix段的double值 <br>
|
||||
* 例如请求URL /pipes/record/query/point:40.0 <br>
|
||||
@@ -642,14 +692,14 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
* 获取指定的header的json值
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param clazz 反序列化的类名
|
||||
* @param type 反序列化的类名
|
||||
* @param name header名
|
||||
*
|
||||
* @return header值
|
||||
*/
|
||||
public <T> T getJsonHeader(Class<T> clazz, String name) {
|
||||
public <T> T getJsonHeader(java.lang.reflect.Type type, String name) {
|
||||
String v = getHeader(name);
|
||||
return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(clazz, v);
|
||||
return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -657,14 +707,14 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param convert JsonConvert对象
|
||||
* @param clazz 反序列化的类名
|
||||
* @param type 反序列化的类名
|
||||
* @param name header名
|
||||
*
|
||||
* @return header值
|
||||
*/
|
||||
public <T> T getJsonHeader(JsonConvert convert, Class<T> clazz, String name) {
|
||||
public <T> T getJsonHeader(JsonConvert convert, java.lang.reflect.Type type, String name) {
|
||||
String v = getHeader(name);
|
||||
return v == null || v.isEmpty() ? null : convert.convertFrom(clazz, v);
|
||||
return v == null || v.isEmpty() ? null : convert.convertFrom(type, v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -691,6 +741,19 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return header.getShortValue(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的short值, 没有返回默认short值
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param name header名
|
||||
* @param defaultValue 默认short值
|
||||
*
|
||||
* @return header值
|
||||
*/
|
||||
public short getShortHeader(int radix, String name, short defaultValue) {
|
||||
return header.getShortValue(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的short值, 没有返回默认short值
|
||||
*
|
||||
@@ -703,6 +766,19 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return header.getShortValue(name, (short) defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的short值, 没有返回默认short值
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param name header名
|
||||
* @param defaultValue 默认short值
|
||||
*
|
||||
* @return header值
|
||||
*/
|
||||
public short getShortHeader(int radix, String name, int defaultValue) {
|
||||
return header.getShortValue(radix, name, (short) defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的int值, 没有返回默认int值
|
||||
*
|
||||
@@ -715,6 +791,19 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return header.getIntValue(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的int值, 没有返回默认int值
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param name header名
|
||||
* @param defaultValue 默认int值
|
||||
*
|
||||
* @return header值
|
||||
*/
|
||||
public int getIntHeader(int radix, String name, int defaultValue) {
|
||||
return header.getIntValue(radix, name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的long值, 没有返回默认long值
|
||||
*
|
||||
@@ -727,6 +816,19 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return header.getLongValue(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的long值, 没有返回默认long值
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param name header名
|
||||
* @param defaultValue 默认long值
|
||||
*
|
||||
* @return header值
|
||||
*/
|
||||
public long getLongHeader(int radix, String name, long defaultValue) {
|
||||
return header.getLongValue(radix, name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的header的float值, 没有返回默认float值
|
||||
*
|
||||
@@ -791,14 +893,14 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
* 获取指定的参数json值
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param clazz 反序列化的类名
|
||||
* @param type 反序列化的类名
|
||||
* @param name 参数名
|
||||
*
|
||||
* @return 参数值
|
||||
*/
|
||||
public <T> T getJsonParameter(Class<T> clazz, String name) {
|
||||
public <T> T getJsonParameter(java.lang.reflect.Type type, String name) {
|
||||
String v = getParameter(name);
|
||||
return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(clazz, v);
|
||||
return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -806,14 +908,14 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param convert JsonConvert对象
|
||||
* @param clazz 反序列化的类名
|
||||
* @param type 反序列化的类名
|
||||
* @param name 参数名
|
||||
*
|
||||
* @return 参数值
|
||||
*/
|
||||
public <T> T getJsonParameter(JsonConvert convert, Class<T> clazz, String name) {
|
||||
public <T> T getJsonParameter(JsonConvert convert, java.lang.reflect.Type type, String name) {
|
||||
String v = getParameter(name);
|
||||
return v == null || v.isEmpty() ? null : convert.convertFrom(clazz, v);
|
||||
return v == null || v.isEmpty() ? null : convert.convertFrom(type, v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -842,6 +944,20 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return params.getShortValue(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的参数short值, 没有返回默认short值
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param name 参数名
|
||||
* @param defaultValue 默认short值
|
||||
*
|
||||
* @return 参数值
|
||||
*/
|
||||
public short getShortParameter(int radix, String name, short defaultValue) {
|
||||
parseBody();
|
||||
return params.getShortValue(radix, name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的参数short值, 没有返回默认short值
|
||||
*
|
||||
@@ -868,6 +984,20 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return params.getIntValue(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的参数int值, 没有返回默认int值
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param name 参数名
|
||||
* @param defaultValue 默认int值
|
||||
*
|
||||
* @return 参数值
|
||||
*/
|
||||
public int getIntParameter(int radix, String name, int defaultValue) {
|
||||
parseBody();
|
||||
return params.getIntValue(radix, name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的参数long值, 没有返回默认long值
|
||||
*
|
||||
@@ -881,6 +1011,20 @@ public class HttpRequest extends Request<HttpContext> {
|
||||
return params.getLongValue(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的参数long值, 没有返回默认long值
|
||||
*
|
||||
* @param radix 进制数
|
||||
* @param name 参数名
|
||||
* @param defaultValue 默认long值
|
||||
*
|
||||
* @return 参数值
|
||||
*/
|
||||
public long getLongParameter(int radix, String name, long defaultValue) {
|
||||
parseBody();
|
||||
return params.getLongValue(radix, name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的参数float值, 没有返回默认float值
|
||||
*
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.logging.*;
|
||||
import java.util.regex.*;
|
||||
import org.redkale.util.AnyValue;
|
||||
@@ -25,9 +24,9 @@ import org.redkale.util.AnyValue;
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public final class HttpResourceServlet extends HttpServlet {
|
||||
public class HttpResourceServlet extends HttpServlet {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(HttpResourceServlet.class.getSimpleName());
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
protected class WatchThread extends Thread {
|
||||
|
||||
@@ -37,7 +36,7 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
|
||||
public WatchThread(File root) throws IOException {
|
||||
this.root = root;
|
||||
this.setName("Servlet-ResourceWatch-Thread");
|
||||
this.setName("HttpResourceServlet-Watch-Thread");
|
||||
this.setDaemon(true);
|
||||
this.watcher = this.root.toPath().getFileSystem().newWatchService();
|
||||
}
|
||||
@@ -62,8 +61,13 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
files.remove(uri);
|
||||
} else if (event.kind() == ENTRY_MODIFY) {
|
||||
FileEntry en = files.get(uri);
|
||||
if (en != null) {
|
||||
Thread.sleep(5000L); //等待update file完毕
|
||||
if (en != null && en.file != null) {
|
||||
long d; //等待update file完毕
|
||||
for (;;) {
|
||||
d = en.file.lastModified();
|
||||
Thread.sleep(2000L);
|
||||
if (d == en.file.lastModified()) break;
|
||||
}
|
||||
en.update();
|
||||
}
|
||||
}
|
||||
@@ -103,8 +107,6 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
|
||||
protected WatchThread watchThread;
|
||||
|
||||
protected Predicate<String> ranges;
|
||||
|
||||
@Override
|
||||
public void init(HttpContext context, AnyValue config) {
|
||||
if (config != null) {
|
||||
@@ -113,15 +115,12 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
if (rootstr.indexOf(':') < 0 && rootstr.indexOf('/') != 0 && System.getProperty("APP_HOME") != null) {
|
||||
rootstr = new File(System.getProperty("APP_HOME"), rootstr).getPath();
|
||||
}
|
||||
String rangesValue = config.getValue("ranges");
|
||||
this.ranges = rangesValue != null ? Pattern.compile(rangesValue).asPredicate() : null;
|
||||
try {
|
||||
this.root = new File(rootstr).getCanonicalFile();
|
||||
} catch (IOException ioe) {
|
||||
this.root = new File(rootstr);
|
||||
}
|
||||
AnyValue cacheconf = config.getAnyValue("cache");
|
||||
if (cacheconf == null) cacheconf = config.getAnyValue("caches"); //兼容旧参数
|
||||
if (cacheconf != null) {
|
||||
this.cachelimit = parseLenth(cacheconf.getValue("limit"), 0 * 1024 * 1024L);
|
||||
this.cachelengthmax = parseLenth(cacheconf.getValue("lengthmax"), 1 * 1024 * 1024L);
|
||||
@@ -162,7 +161,7 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
private static long parseLenth(String value, long defValue) {
|
||||
protected static long parseLenth(String value, long defValue) {
|
||||
if (value == null) return defValue;
|
||||
value = value.toUpperCase().replace("B", "");
|
||||
if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
|
||||
@@ -191,7 +190,7 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
}
|
||||
//System.out.println(request);
|
||||
FileEntry entry;
|
||||
if (watchThread == null) {
|
||||
if (watchThread == null && files.isEmpty()) {
|
||||
entry = createFileEntry(uri);
|
||||
} else { //有缓存
|
||||
entry = files.computeIfAbsent(uri, x -> createFileEntry(x));
|
||||
@@ -200,11 +199,13 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
if (finest) logger.log(Level.FINEST, "Not found resource (404), request = " + request);
|
||||
response.finish404();
|
||||
} else {
|
||||
response.finishFile(entry.file, entry.content);
|
||||
//file = null 表示资源内容在内存而不是在File中
|
||||
//file = null 时必须传 filename
|
||||
response.finishFile(entry.file == null ? entry.filename : null, entry.file, entry.content);
|
||||
}
|
||||
}
|
||||
|
||||
private FileEntry createFileEntry(String uri) {
|
||||
protected FileEntry createFileEntry(String uri) {
|
||||
File rfile = new File(root, uri);
|
||||
File file = rfile;
|
||||
if (file.isDirectory()) file = new File(rfile, this.indexHtml);
|
||||
@@ -221,21 +222,52 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
return en;
|
||||
}
|
||||
|
||||
private static final class FileEntry {
|
||||
protected static class FileEntry {
|
||||
|
||||
final File file;
|
||||
protected final String filename;
|
||||
|
||||
private final HttpResourceServlet servlet;
|
||||
protected final File file; //如果所有资源文件打包成zip文件则file=null
|
||||
|
||||
ByteBuffer content;
|
||||
protected final HttpResourceServlet servlet;
|
||||
|
||||
protected ByteBuffer content;
|
||||
|
||||
public FileEntry(final HttpResourceServlet servlet, File file) {
|
||||
this.servlet = servlet;
|
||||
this.file = file;
|
||||
this.filename = file.getName();
|
||||
update();
|
||||
}
|
||||
|
||||
public FileEntry(final HttpResourceServlet servlet, String filename, ByteBuffer content) {
|
||||
this.servlet = servlet;
|
||||
this.file = null;
|
||||
this.filename = filename;
|
||||
this.content = content.asReadOnlyBuffer();
|
||||
this.servlet.cachedLength.add(this.content.remaining());
|
||||
}
|
||||
|
||||
public FileEntry(final HttpResourceServlet servlet, String filename, InputStream in) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
byte[] bytes = new byte[10240];
|
||||
int pos;
|
||||
while ((pos = in.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, pos);
|
||||
}
|
||||
byte[] bs = out.toByteArray();
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(bs.length);
|
||||
buf.put(bs);
|
||||
buf.flip();
|
||||
|
||||
this.servlet = servlet;
|
||||
this.file = null;
|
||||
this.filename = filename;
|
||||
this.content = buf.asReadOnlyBuffer();
|
||||
this.servlet.cachedLength.add(this.content.remaining());
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (this.file == null) return;
|
||||
if (this.content != null) {
|
||||
this.servlet.cachedLength.add(0L - this.content.remaining());
|
||||
this.content = null;
|
||||
@@ -259,7 +291,7 @@ public final class HttpResourceServlet extends HttpServlet {
|
||||
this.content = buf.asReadOnlyBuffer();
|
||||
this.servlet.cachedLength.add(this.content.remaining());
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " update FileEntry(" + file + ") erroneous", e);
|
||||
this.servlet.logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " update FileEntry(" + file + ") erroneous", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.redkale.util.*;
|
||||
/**
|
||||
* Http响应包 与javax.servlet.http.HttpServletResponse 基本类似。
|
||||
* 同时提供发送json的系列接口: public void finishJson(Type type, Object obj)
|
||||
* RedKale提倡http+json的接口风格, 所以主要输出的数据格式为json, 同时提供异步接口。
|
||||
* Redkale提倡http+json的接口风格, 所以主要输出的数据格式为json, 同时提供异步接口。
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
@@ -195,6 +195,29 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加Cookie值
|
||||
*
|
||||
* @param cookies cookie
|
||||
*
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public HttpResponse addCookie(Collection<HttpCookie> cookies) {
|
||||
if (cookies == null || cookies.isEmpty()) return this;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象以JSON格式输出
|
||||
*
|
||||
@@ -258,7 +281,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
this.contentType = "text/plain; charset=utf-8";
|
||||
if (ret != null && !ret.isSuccess()) {
|
||||
this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
|
||||
this.header.addValue("retcode", ret.getRetinfo());
|
||||
this.header.addValue("retinfo", ret.getRetinfo());
|
||||
}
|
||||
finish(request.getJsonConvert().convertTo(context.getBufferSupplier(), ret));
|
||||
}
|
||||
@@ -273,7 +296,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
this.contentType = "text/plain; charset=utf-8";
|
||||
if (ret != null && !ret.isSuccess()) {
|
||||
this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
|
||||
this.header.addValue("retcode", ret.getRetinfo());
|
||||
this.header.addValue("retinfo", ret.getRetinfo());
|
||||
}
|
||||
finish(convert.convertTo(context.getBufferSupplier(), ret));
|
||||
}
|
||||
@@ -502,6 +525,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
|
||||
/**
|
||||
* 将指定文件句柄或文件内容按指定文件名输出,若fileBody不为null则只输出fileBody内容
|
||||
* file 与 fileBody 不能同时为空
|
||||
* file 与 filename 也不能同时为空
|
||||
*
|
||||
* @param filename 输出文件名
|
||||
* @param file 输出文件
|
||||
@@ -510,19 +535,20 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
protected void finishFile(final String filename, final File file, ByteBuffer fileBody) throws IOException {
|
||||
if (file == null || !file.isFile() || !file.canRead()) {
|
||||
if ((file == null || !file.isFile() || !file.canRead()) && fileBody == null) {
|
||||
finish404();
|
||||
return;
|
||||
}
|
||||
if (fileBody != null) fileBody = fileBody.duplicate().asReadOnlyBuffer();
|
||||
final long length = file.length();
|
||||
final long length = file == null ? fileBody.remaining() : file.length();
|
||||
final String match = request.getHeader("If-None-Match");
|
||||
if (match != null && (file.lastModified() + "-" + length).equals(match)) {
|
||||
final String etag = (file == null ? 0L : file.lastModified()) + "-" + length;
|
||||
if (match != null && etag.equals(match)) {
|
||||
finish304();
|
||||
return;
|
||||
}
|
||||
this.contentLength = fileBody == null ? file.length() : fileBody.remaining();
|
||||
if (filename != null && !filename.isEmpty()) {
|
||||
this.contentLength = length;
|
||||
if (filename != null && !filename.isEmpty() && file != null) {
|
||||
addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
|
||||
}
|
||||
this.contentType = MimeType.getByFilename(filename == null || filename.isEmpty() ? file.getName() : filename);
|
||||
@@ -536,14 +562,14 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
int pos = range.indexOf('-');
|
||||
start = pos == 0 ? 0 : Integer.parseInt(range.substring(0, pos));
|
||||
long end = (pos == range.length() - 1) ? -1 : Long.parseLong(range.substring(pos + 1));
|
||||
long clen = end > 0 ? (end - start + 1) : (file.length() - start);
|
||||
long clen = end > 0 ? (end - start + 1) : (length - start);
|
||||
this.status = 206;
|
||||
addHeader("Accept-Ranges", "bytes");
|
||||
addHeader("Content-Range", "bytes " + start + "-" + (end > 0 ? end : length - 1) + "/" + length);
|
||||
this.contentLength = clen;
|
||||
len = end > 0 ? clen : end;
|
||||
}
|
||||
this.addHeader("ETag", file.lastModified() + "-" + length);
|
||||
this.addHeader("ETag", etag);
|
||||
ByteBuffer hbuffer = createHeader();
|
||||
hbuffer.flip();
|
||||
if (fileBody == null) {
|
||||
@@ -690,6 +716,21 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加Header值
|
||||
*
|
||||
* @param map header值
|
||||
*
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public HttpResponse addHeader(Map<String, ?> map) {
|
||||
if (map == null || map.isEmpty()) return this;
|
||||
for (Map.Entry<String, ?> en : map.entrySet()) {
|
||||
this.header.addValue(en.getKey(), String.valueOf(en.getValue()));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置状态码
|
||||
*
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.HttpCookie;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.redkale.net.*;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.util.*;
|
||||
import org.redkale.watch.WatchFactory;
|
||||
|
||||
@@ -35,10 +37,69 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
|
||||
super.init(config);
|
||||
}
|
||||
|
||||
public HttpServer addHttpServlet(String prefix, HttpServlet servlet, String... mappings) {
|
||||
this.prepare.addServlet(servlet, prefix, null, mappings);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpServer addHttpServlet(HttpServlet servlet, String... mappings) {
|
||||
this.prepare.addServlet(servlet, null, null, mappings);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addHttpServlet(HttpServlet servlet, final String prefix, AnyValue conf, String... mappings) {
|
||||
this.prepare.addServlet(servlet, prefix, conf, mappings);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(
|
||||
final String name, Class<S> serviceType, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) {
|
||||
RestHttpServlet servlet = null;
|
||||
for (final HttpServlet item : ((HttpPrepareServlet) this.prepare).getServlets()) {
|
||||
if (!(item instanceof RestHttpServlet)) continue;
|
||||
if (item.getClass().getAnnotation(Rest.RestDynamic.class) == null) continue;
|
||||
try {
|
||||
Field field = item.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
|
||||
if (serviceType.equals(field.getType())) {
|
||||
servlet = (RestHttpServlet) item;
|
||||
break;
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
System.err.println("serviceType = " + serviceType + ", servletClass = " + item.getClass());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
final boolean first = servlet == null;
|
||||
if (servlet == null) servlet = Rest.createRestServlet(baseServletClass, serviceType);
|
||||
try { //若提供动态变更Service服务功能,则改Rest服务无法做出相应更新
|
||||
Field field = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
|
||||
field.setAccessible(true);
|
||||
|
||||
Field mapfield = servlet.getClass().getDeclaredField(Rest.REST_SERVICEMAP_FIELD_NAME);
|
||||
mapfield.setAccessible(true);
|
||||
|
||||
Service firstService = (Service) field.get(servlet);
|
||||
if (name.isEmpty()) {
|
||||
field.set(servlet, service);
|
||||
firstService = service;
|
||||
}
|
||||
Map map = (Map) mapfield.get(servlet);
|
||||
if (map == null && !name.isEmpty()) map = new HashMap();
|
||||
if (map != null) {
|
||||
map.put(name, service);
|
||||
if (firstService != null) map.put("", firstService);
|
||||
}
|
||||
mapfield.set(servlet, map);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(serviceType + " generate rest servlet error", e);
|
||||
}
|
||||
if (first) this.prepare.addServlet(servlet, prefix, conf);
|
||||
return servlet;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected HttpContext createContext() {
|
||||
|
||||
@@ -18,14 +18,4 @@ public abstract class HttpServlet extends Servlet<HttpContext, HttpRequest, Http
|
||||
|
||||
String _prefix = ""; //当前HttpServlet的path前缀
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p> 详情见: http://redkale.org
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class MimeType {
|
||||
@@ -172,20 +174,20 @@ public class MimeType {
|
||||
}
|
||||
|
||||
public static String get(String extension) {
|
||||
return contentTypes.getOrDefault(extension, "text/plain");
|
||||
return contentTypes.getOrDefault(extension.toLowerCase(), "text/plain");
|
||||
}
|
||||
|
||||
public static String get(String extension, String defaultCt) {
|
||||
return contentTypes.getOrDefault(extension, defaultCt);
|
||||
return contentTypes.getOrDefault(extension.toLowerCase(), defaultCt);
|
||||
}
|
||||
|
||||
public static boolean contains(String extension) {
|
||||
return contentTypes.containsKey(extension);
|
||||
return contentTypes.containsKey(extension.toLowerCase());
|
||||
}
|
||||
|
||||
public static void add(String extension, String contentType) {
|
||||
if (extension != null && extension.length() != 0 && contentType != null && contentType.length() != 0) {
|
||||
contentTypes.put(extension, contentType);
|
||||
contentTypes.put(extension.toLowerCase(), contentType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +196,7 @@ public class MimeType {
|
||||
int newEnd = fileName.lastIndexOf('#');
|
||||
if (newEnd == -1) newEnd = length;
|
||||
int i = fileName.lastIndexOf('.', newEnd);
|
||||
return (i < 0) ? null : get(fileName.substring(i + 1, newEnd));
|
||||
return (i < 0) ? null : get(fileName.substring(i + 1, newEnd).toLowerCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1059
src/org/redkale/net/http/Rest.java
Normal file
1059
src/org/redkale/net/http/Rest.java
Normal file
File diff suppressed because it is too large
Load Diff
28
src/org/redkale/net/http/RestAddress.java
Normal file
28
src/org/redkale/net/http/RestAddress.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能注解于Service类的方法的String参数或参数内的String字段
|
||||
* <p>
|
||||
* 用于获取HTTP请求端的IP地址 HttpRequest.getRemoteAddr
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({PARAMETER, FIELD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface RestAddress {
|
||||
|
||||
}
|
||||
30
src/org/redkale/net/http/RestCookie.java
Normal file
30
src/org/redkale/net/http/RestCookie.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能注解于Service类的方法的String参数或参数内的String字段
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({PARAMETER, FIELD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface RestCookie {
|
||||
|
||||
String name(); //cookie名
|
||||
|
||||
int radix() default 10; //转换数字byte/short/int/long时所用的进制数, 默认10进制
|
||||
|
||||
String comment() default ""; //备注描述
|
||||
}
|
||||
30
src/org/redkale/net/http/RestHeader.java
Normal file
30
src/org/redkale/net/http/RestHeader.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能注解于Service类的方法的参数或参数内的String字段
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({PARAMETER, FIELD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface RestHeader {
|
||||
|
||||
String name(); //参数名
|
||||
|
||||
int radix() default 10; //转换数字byte/short/int/long时所用的进制数, 默认10进制
|
||||
|
||||
String comment() default ""; //备注描述
|
||||
}
|
||||
49
src/org/redkale/net/http/RestHttpServlet.java
Normal file
49
src/org/redkale/net/http/RestHttpServlet.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.redkale.util.Attribute;
|
||||
|
||||
/**
|
||||
*
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <T> 当前用户对象类型
|
||||
*/
|
||||
public abstract class RestHttpServlet<T> extends HttpBaseServlet {
|
||||
|
||||
protected abstract T currentUser(HttpRequest req) throws IOException;
|
||||
|
||||
protected void finishJson(final HttpResponse response, RestOutput output) throws IOException {
|
||||
if (output != null) {
|
||||
response.addHeader(output.getHeaders());
|
||||
response.addCookie(output.getCookies());
|
||||
}
|
||||
response.finishJson(output == null ? null : 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());
|
||||
}
|
||||
|
||||
Attribute[] _paramAttrs; // 为null表示无DynCall处理,index=0固定为null, 其他为参数标记的DynCall回调方法
|
||||
|
||||
protected void _callParameter(final HttpResponse response, final Object... params) {
|
||||
if (_paramAttrs == null) return;
|
||||
for (int i = 1; i < _paramAttrs.length; i++) {
|
||||
org.redkale.util.Attribute attr = _paramAttrs[i];
|
||||
if (attr == null) continue;
|
||||
|
||||
//convert.convertTo(out, attr.type(), attr.get(params[i - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/org/redkale/net/http/RestMapping.java
Normal file
49
src/org/redkale/net/http/RestMapping.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* 只能依附在Service实现类的public方法上
|
||||
* value默认为"/" + Service的类名去掉Service字样的小写字符串 (如HelloService,的默认路径为/hello)。
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({METHOD})
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(RestMappings.class)
|
||||
public @interface RestMapping {
|
||||
|
||||
boolean ignore() default false; //是否屏蔽该方法的转换
|
||||
|
||||
/**
|
||||
* 请求的方法名, 不能含特殊字符
|
||||
* 默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前)
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
String comment() default ""; //备注描述, 对应@WebAction.comment
|
||||
|
||||
boolean auth() default false; //是否鉴权,默认不鉴权, 对应@AuthIgnore
|
||||
|
||||
int actionid() default 0; //操作ID值,鉴权时用到, 对应@WebAction.actionid
|
||||
|
||||
int cachetimeout() default 0; // 结果缓存的秒数, 为0表示不缓存, 对应@HttpCacheable.timeout
|
||||
|
||||
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@WebAction.methods
|
||||
|
||||
//String contentType() default ""; //设置Response的ContentType 默认值为 text/plain; charset=utf-8
|
||||
String jsvar() default ""; //以application/javascript输出对象是指明js的对象名,该值存在时则忽略contentType()的值
|
||||
}
|
||||
26
src/org/redkale/net/http/RestMappings.java
Normal file
26
src/org/redkale/net/http/RestMappings.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* RestMapping 的多用类
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({METHOD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface RestMappings {
|
||||
|
||||
RestMapping[] value();
|
||||
}
|
||||
69
src/org/redkale/net/http/RestOutput.java
Normal file
69
src/org/redkale/net/http/RestOutput.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <T> 结果对象的类型
|
||||
*/
|
||||
public class RestOutput<T> {
|
||||
|
||||
private Map<String, String> headers;
|
||||
|
||||
private List<HttpCookie> cookies;
|
||||
|
||||
private T result;
|
||||
|
||||
public RestOutput() {
|
||||
}
|
||||
|
||||
public RestOutput(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public void addHeader(String name, Serializable value) {
|
||||
if (this.headers == null) this.headers = new HashMap<>();
|
||||
this.headers.put(name, String.valueOf(value));
|
||||
}
|
||||
|
||||
public void addCookie(HttpCookie cookie) {
|
||||
if (this.cookies == null) this.cookies = new ArrayList<>();
|
||||
this.cookies.add(cookie);
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public List<HttpCookie> getCookies() {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
public void setCookies(List<HttpCookie> cookies) {
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
}
|
||||
32
src/org/redkale/net/http/RestParam.java
Normal file
32
src/org/redkale/net/http/RestParam.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能依附在Service类的方法的参数上, name值不能是'&'
|
||||
* name='#'表示截取uri最后一段
|
||||
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({PARAMETER})
|
||||
@Retention(RUNTIME)
|
||||
public @interface RestParam {
|
||||
|
||||
String name(); //参数名
|
||||
|
||||
int radix() default 10; //转换数字byte/short/int/long时所用的进制数, 默认10进制
|
||||
|
||||
String comment() default ""; //备注描述
|
||||
}
|
||||
59
src/org/redkale/net/http/RestService.java
Normal file
59
src/org/redkale/net/http/RestService.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能依附在Service类上,name默认为Service的类名小写并去掉Service字样及后面的字符串 (如HelloService/HelloServiceImpl,的默认路径为 hello)。
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({TYPE})
|
||||
@Retention(RUNTIME)
|
||||
public @interface RestService {
|
||||
|
||||
/**
|
||||
* 模块名, 只能是模块名,不能含特殊字符, 只能小写字母+数字,且不能以数字开头
|
||||
*
|
||||
* @return 模块名
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* 模块ID值,鉴权时用到, 对应@WebServlet.moduleid
|
||||
*
|
||||
* @return 模块ID值
|
||||
*/
|
||||
int moduleid() default 0;
|
||||
|
||||
/**
|
||||
* 是否屏蔽该类的转换
|
||||
*
|
||||
* @return 默认false
|
||||
*/
|
||||
boolean ignore() default false;
|
||||
|
||||
/**
|
||||
* 同@WebServlet的repair属性
|
||||
*
|
||||
* @return 默认true
|
||||
*/
|
||||
boolean repair() default true;
|
||||
|
||||
/**
|
||||
* 备注描述
|
||||
*
|
||||
* @return 备注描述
|
||||
*/
|
||||
String comment() default "";
|
||||
}
|
||||
26
src/org/redkale/net/http/RestSessionid.java
Normal file
26
src/org/redkale/net/http/RestSessionid.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能注解于Service类的方法的参数或参数内的String字段
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({PARAMETER, FIELD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface RestSessionid {
|
||||
|
||||
boolean create() default false;
|
||||
}
|
||||
@@ -11,7 +11,9 @@ import java.lang.annotation.*;
|
||||
* 功能同JSR 315 (java-servlet 3.0) 规范中的 @WebServlet
|
||||
*
|
||||
*
|
||||
* <p> 详情见: http://redkale.org
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Documented
|
||||
@@ -28,4 +30,6 @@ public @interface WebServlet {
|
||||
int moduleid() default 0;
|
||||
|
||||
WebInitParam[] initParams() default {};
|
||||
|
||||
String comment() default ""; //备注描述
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public abstract class WebSocketNode {
|
||||
@Resource(name = Application.RESNAME_SERVER_ADDR)
|
||||
protected InetSocketAddress localSncpAddress; //为SncpServer的服务address
|
||||
|
||||
@DynRemote
|
||||
@RpcRemote
|
||||
protected WebSocketNode remoteNode;
|
||||
|
||||
//存放所有用户分布在节点上的队列信息,Set<InetSocketAddress> 为 sncpnode 的集合
|
||||
@@ -58,16 +58,16 @@ public abstract class WebSocketNode {
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract List<String> getOnlineRemoteAddresses(@DynTargetAddress InetSocketAddress targetAddress, Serializable groupid);
|
||||
protected abstract List<String> getOnlineRemoteAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid);
|
||||
|
||||
protected abstract int sendMessage(@DynTargetAddress InetSocketAddress targetAddress, Serializable groupid, boolean recent, Serializable message, boolean last);
|
||||
protected abstract int sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid, boolean recent, Serializable message, boolean last);
|
||||
|
||||
protected abstract void connect(Serializable groupid, InetSocketAddress addr);
|
||||
|
||||
protected abstract void disconnect(Serializable groupid, InetSocketAddress addr);
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
protected List<String> remoteOnlineRemoteAddresses(@DynTargetAddress InetSocketAddress targetAddress, Serializable groupid) {
|
||||
protected List<String> remoteOnlineRemoteAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid) {
|
||||
if (remoteNode == null) return null;
|
||||
try {
|
||||
return remoteNode.getOnlineRemoteAddresses(targetAddress, groupid);
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.redkale.util.*;
|
||||
* WebSocketServlet
|
||||
* |
|
||||
* |
|
||||
* WebSocketEngine & WebSocketNode
|
||||
* WebSocketEngine & WebSocketNode
|
||||
* / \
|
||||
* / \
|
||||
* / \
|
||||
|
||||
@@ -17,6 +17,7 @@ import jdk.internal.org.objectweb.asm.*;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import org.redkale.convert.bson.BsonConvert;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.net.Transport;
|
||||
import org.redkale.net.sncp.SncpClient.SncpAction;
|
||||
import org.redkale.service.*;
|
||||
@@ -79,6 +80,7 @@ public abstract class Sncp {
|
||||
* 对类名或者name字符串进行hash。
|
||||
*
|
||||
* @param name String
|
||||
*
|
||||
* @return hash值
|
||||
*/
|
||||
public static DLong hash(final String name) {
|
||||
@@ -155,7 +157,10 @@ public abstract class Sncp {
|
||||
* public final class _DynLocalTestService extends TestService{
|
||||
*
|
||||
* @Resource
|
||||
* private BsonConvert _redkale_convert;
|
||||
* private BsonConvert _redkale_bsonConvert;
|
||||
*
|
||||
* @Resource
|
||||
* private JsonConvert _redkale_jsonConvert;
|
||||
*
|
||||
* private Transport _redkale_sameGroupTransport;
|
||||
*
|
||||
@@ -179,8 +184,8 @@ public abstract class Sncp {
|
||||
* public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
|
||||
* if(selfrunnable) super.createSomeThing(bean);
|
||||
* if (_redkale_client== null) return;
|
||||
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_convert, _sameGroupTransport, 0, true, false, false, bean);
|
||||
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_convert, _diffGroupTransports, 0, true, true, false, bean);
|
||||
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _sameGroupTransport, 0, true, false, false, bean);
|
||||
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _diffGroupTransports, 0, true, true, false, bean);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
@@ -192,8 +197,8 @@ public abstract class Sncp {
|
||||
* public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
|
||||
* String rs = super.updateSomeThing(id);
|
||||
* if (_redkale_client== null) return;
|
||||
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_convert, _sameGroupTransport, 1, true, false, false, id);
|
||||
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_convert, _diffGroupTransports, 1, true, true, false, id);
|
||||
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _sameGroupTransport, 1, true, false, false, id);
|
||||
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _diffGroupTransports, 1, true, true, false, id);
|
||||
* return rs;
|
||||
* }
|
||||
* }
|
||||
@@ -204,6 +209,7 @@ public abstract class Sncp {
|
||||
* @param <T> Service子类
|
||||
* @param name 资源名
|
||||
* @param serviceClass Service类
|
||||
*
|
||||
* @return Service实例
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -217,7 +223,8 @@ public abstract class Sncp {
|
||||
final String supDynName = serviceClass.getName().replace('.', '/');
|
||||
final String clientName = SncpClient.class.getName().replace('.', '/');
|
||||
final String clientDesc = Type.getDescriptor(SncpClient.class);
|
||||
final String convertDesc = Type.getDescriptor(BsonConvert.class);
|
||||
final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class);
|
||||
final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
|
||||
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
|
||||
final String transportDesc = Type.getDescriptor(Transport.class);
|
||||
final String transportsDesc = Type.getDescriptor(Transport[].class);
|
||||
@@ -275,7 +282,13 @@ public abstract class Sncp {
|
||||
}
|
||||
|
||||
{
|
||||
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_convert", convertDesc, null, null);
|
||||
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null);
|
||||
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
|
||||
av0.visitEnd();
|
||||
fv.visitEnd();
|
||||
}
|
||||
{
|
||||
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_jsonConvert", jsonConvertDesc, null, null);
|
||||
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
|
||||
av0.visitEnd();
|
||||
fv.visitEnd();
|
||||
@@ -481,20 +494,24 @@ public abstract class Sncp {
|
||||
|
||||
mv.visitVarInsn(ALOAD, 0);//调用 _client
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
|
||||
mv.visitVarInsn(ALOAD, 0); //传递 _convert
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_convert", convertDesc);
|
||||
mv.visitVarInsn(ALOAD, 0); //传递 _bsonConvert
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_bsonConvert", bsonConvertDesc);
|
||||
mv.visitVarInsn(ALOAD, 0); //传递 _jsonConvert
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_jsonConvert", jsonConvertDesc);
|
||||
mv.visitVarInsn(ALOAD, 0); //传递 _sameGroupTransport
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sameGroupTransport", transportDesc);
|
||||
|
||||
final int preparams = 4; //调用selfrunnable之前的参数个数; _client/_bsonConvert/_jsonConvert/_sameGroupTransport
|
||||
|
||||
if (index <= 5) { //第几个 SncpAction
|
||||
mv.visitInsn(ICONST_0 + index);
|
||||
} else {
|
||||
mv.visitIntInsn(BIPUSH, index);
|
||||
}
|
||||
if (paramtypes.length + 3 <= 5) { //参数总数量
|
||||
mv.visitInsn(ICONST_0 + paramtypes.length + 3);
|
||||
if (paramtypes.length + preparams <= 5) { //参数总数量
|
||||
mv.visitInsn(ICONST_0 + paramtypes.length + preparams);
|
||||
} else {
|
||||
mv.visitIntInsn(BIPUSH, paramtypes.length + 3);
|
||||
mv.visitIntInsn(BIPUSH, paramtypes.length + preparams);
|
||||
}
|
||||
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
@@ -517,7 +534,7 @@ public abstract class Sncp {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
mv.visitInsn(AASTORE);
|
||||
|
||||
int insn = 3;
|
||||
int insn = 3; //空3给selfrunnable、samerunnable、diffrunnable
|
||||
for (int j = 0; j < paramtypes.length; j++) {
|
||||
final Class pt = paramtypes[j];
|
||||
mv.visitInsn(DUP);
|
||||
@@ -544,7 +561,7 @@ public abstract class Sncp {
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteSameGroup" : "remoteSameGroup", "(" + convertDesc + transportDesc + "I[Ljava/lang/Object;)V", false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteSameGroup" : "remoteSameGroup", "(" + bsonConvertDesc + jsonConvertDesc + transportDesc + "I[Ljava/lang/Object;)V", false);
|
||||
mv.visitLabel(sameLabel);
|
||||
//---------------------------- 调用diffrun ---------------------------------
|
||||
mv.visitVarInsn(ILOAD, 3); //读取 diffrunnable
|
||||
@@ -554,7 +571,9 @@ public abstract class Sncp {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_convert", convertDesc);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_bsonConvert", bsonConvertDesc);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_jsonConvert", jsonConvertDesc);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_diffGroupTransports", transportsDesc);
|
||||
|
||||
@@ -563,10 +582,10 @@ public abstract class Sncp {
|
||||
} else {
|
||||
mv.visitIntInsn(BIPUSH, index);
|
||||
}
|
||||
if (paramtypes.length + 3 <= 5) { //参数总数量
|
||||
mv.visitInsn(ICONST_0 + paramtypes.length + 3);
|
||||
if (paramtypes.length + preparams <= 5) { //参数总数量
|
||||
mv.visitInsn(ICONST_0 + paramtypes.length + preparams);
|
||||
} else {
|
||||
mv.visitIntInsn(BIPUSH, paramtypes.length + 3);
|
||||
mv.visitIntInsn(BIPUSH, paramtypes.length + preparams);
|
||||
}
|
||||
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
@@ -589,7 +608,7 @@ public abstract class Sncp {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
mv.visitInsn(AASTORE);
|
||||
|
||||
insn = 3;
|
||||
insn = 3;//空3给selfrunnable、samerunnable、diffrunnable
|
||||
for (int j = 0; j < paramtypes.length; j++) {
|
||||
final Class pt = paramtypes[j];
|
||||
mv.visitInsn(DUP);
|
||||
@@ -616,7 +635,7 @@ public abstract class Sncp {
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteDiffGroup" : "remoteDiffGroup", "(" + convertDesc + transportsDesc + "I[Ljava/lang/Object;)V", false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteDiffGroup" : "remoteDiffGroup", "(" + bsonConvertDesc + jsonConvertDesc + transportsDesc + "I[Ljava/lang/Object;)V", false);
|
||||
mv.visitLabel(diffLabel);
|
||||
|
||||
if (returnType == void.class) {
|
||||
@@ -712,6 +731,7 @@ public abstract class Sncp {
|
||||
* @param clientAddress 本地IP地址
|
||||
* @param sameGroupTransport 同组的通信组件
|
||||
* @param diffGroupTransports 异组的通信组件列表
|
||||
*
|
||||
* @return Service的本地模式实例
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -729,7 +749,7 @@ public abstract class Sncp {
|
||||
for (Field field : loop.getDeclaredFields()) {
|
||||
int mod = field.getModifiers();
|
||||
if (Modifier.isFinal(mod) || Modifier.isStatic(mod)) continue;
|
||||
if (field.getAnnotation(DynRemote.class) == null) continue;
|
||||
if (field.getAnnotation(RpcRemote.class) == null) continue;
|
||||
if (!field.getType().isAssignableFrom(newClazz)) continue;
|
||||
field.setAccessible(true);
|
||||
if (remoteTransport == null) {
|
||||
@@ -761,7 +781,7 @@ public abstract class Sncp {
|
||||
try {
|
||||
Field e = newClazz.getDeclaredField(FIELDPREFIX + "_client");
|
||||
e.setAccessible(true);
|
||||
client = new SncpClient(name, serviceClass, executor, false, newClazz, clientAddress);
|
||||
client = new SncpClient(name, serviceClass, rs, executor, false, newClazz, clientAddress);
|
||||
e.set(rs, client);
|
||||
} catch (NoSuchFieldException ne) {
|
||||
}
|
||||
@@ -771,6 +791,7 @@ public abstract class Sncp {
|
||||
sb.append(newClazz.getName()).append("{name = '").append(name).append("'");
|
||||
if (client != null) {
|
||||
sb.append(", serviceid = ").append(client.getServiceid());
|
||||
sb.append(", serviceversion = ").append(client.getServiceversion());
|
||||
sb.append(", action.size = ").append(client.getActionCount());
|
||||
List<String> groups = new ArrayList<>();
|
||||
if (sameGroupTransport != null) groups.add(sameGroupTransport.getName());
|
||||
@@ -825,7 +846,10 @@ public abstract class Sncp {
|
||||
* public final class _DynRemoteTestService extends TestService{
|
||||
*
|
||||
* @Resource
|
||||
* private BsonConvert _redkale_convert;
|
||||
* private BsonConvert _redkale_bsonConvert;
|
||||
*
|
||||
* @Resource
|
||||
* private JsonConvert _redkale_jsonConvert;
|
||||
*
|
||||
* private Transport _redkale_transport;
|
||||
*
|
||||
@@ -840,27 +864,27 @@ public abstract class Sncp {
|
||||
*
|
||||
* @SncpDyn(remote = false, index = 0)
|
||||
* public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
|
||||
* _redkale_client.remote(_redkale_convert, _redkale_transport, 0, selfrunnable, samerunnable, diffrunnable, bean);
|
||||
* _redkale_client.remote(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_transport, 0, selfrunnable, samerunnable, diffrunnable, bean);
|
||||
* }
|
||||
*
|
||||
* @SncpDyn(remote = false, index = 1)
|
||||
* public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
|
||||
* return _redkale_client.remote(_redkale_convert, _redkale_transport, 1, selfrunnable, samerunnable, diffrunnable, id);
|
||||
* return _redkale_client.remote(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_transport, 1, selfrunnable, samerunnable, diffrunnable, id);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void createSomeThing(TestBean bean){
|
||||
* _redkale_client.remote(_redkale_convert, _redkale_transport, 2, bean);
|
||||
* _redkale_client.remote(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_transport, 2, bean);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public String findSomeThing(){
|
||||
* return _redkale_client.remote(_redkale_convert, _redkale_transport, 3);
|
||||
* return _redkale_client.remote(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_transport, 3);
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public String updateSomeThing(String id){
|
||||
* return _redkale_client.remote(_redkale_convert, _redkale_transport, 4, id);
|
||||
* return _redkale_client.remote(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_transport, 4, id);
|
||||
* }
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
@@ -888,15 +912,16 @@ public abstract class Sncp {
|
||||
final String clientName = SncpClient.class.getName().replace('.', '/');
|
||||
final String clientDesc = Type.getDescriptor(SncpClient.class);
|
||||
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
|
||||
final String convertDesc = Type.getDescriptor(BsonConvert.class);
|
||||
final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class);
|
||||
final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
|
||||
final String transportDesc = Type.getDescriptor(Transport.class);
|
||||
final String anyValueDesc = Type.getDescriptor(AnyValue.class);
|
||||
ClassLoader loader = Sncp.class.getClassLoader();
|
||||
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceClass.getSimpleName();
|
||||
final SncpClient client = new SncpClient(name, serviceClass, executor, true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress);
|
||||
try {
|
||||
Class newClazz = Class.forName(newDynName.replace('/', '.'));
|
||||
T rs = (T) newClazz.newInstance();
|
||||
SncpClient client = new SncpClient(name, serviceClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress);
|
||||
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
|
||||
c.setAccessible(true);
|
||||
c.set(rs, client);
|
||||
@@ -906,7 +931,8 @@ public abstract class Sncp {
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(newClazz.getName()).append("{name = '").append(name);
|
||||
sb.append("', serviceid = ").append(client.getServiceid());
|
||||
sb.append("', serviceid = '").append(client.getServiceid());
|
||||
sb.append("', serviceversion = ").append(client.getServiceversion());
|
||||
sb.append(", action.size = ").append(client.getActionCount());
|
||||
sb.append(", address = ").append(clientAddress).append(", groups = ").append(transport == null ? null : transport.getName());
|
||||
sb.append(", remoteaddrs = ").append(transport == null ? null : Arrays.asList(transport.getRemoteAddresses()));
|
||||
@@ -958,7 +984,13 @@ public abstract class Sncp {
|
||||
}
|
||||
}
|
||||
{
|
||||
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_convert", convertDesc, null, null);
|
||||
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null);
|
||||
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
|
||||
av0.visitEnd();
|
||||
fv.visitEnd();
|
||||
}
|
||||
{
|
||||
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_jsonConvert", jsonConvertDesc, null, null);
|
||||
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
|
||||
av0.visitEnd();
|
||||
fv.visitEnd();
|
||||
@@ -1015,7 +1047,7 @@ public abstract class Sncp {
|
||||
mv.visitEnd();
|
||||
}
|
||||
int i = -1;
|
||||
for (final SncpAction entry : client.actions) {
|
||||
for (final SncpAction entry : SncpClient.getSncpActions(realed ? createLocalServiceClass(name, serviceClass) : serviceClass)) {
|
||||
final int index = ++i;
|
||||
final java.lang.reflect.Method method = entry.method;
|
||||
{
|
||||
@@ -1032,7 +1064,9 @@ public abstract class Sncp {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_convert", convertDesc);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_bsonConvert", bsonConvertDesc);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_jsonConvert", jsonConvertDesc);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_transport", transportDesc);
|
||||
if (index <= 5) {
|
||||
@@ -1079,7 +1113,7 @@ public abstract class Sncp {
|
||||
}
|
||||
}
|
||||
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "remote", "(" + convertDesc + transportDesc + "I[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "remote", "(" + bsonConvertDesc + jsonConvertDesc + transportDesc + "I[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
//mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||
if (method.getGenericReturnType() == void.class) {
|
||||
mv.visitInsn(POP);
|
||||
@@ -1124,6 +1158,7 @@ public abstract class Sncp {
|
||||
T rs = (T) newClazz.newInstance();
|
||||
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
|
||||
c.setAccessible(true);
|
||||
SncpClient client = new SncpClient(name, serviceClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress);
|
||||
c.set(rs, client);
|
||||
Field t = newClazz.getDeclaredField(FIELDPREFIX + "_transport");
|
||||
t.setAccessible(true);
|
||||
@@ -1132,6 +1167,7 @@ public abstract class Sncp {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(newClazz.getName()).append("{name = '").append(name);
|
||||
sb.append("', serviceid = ").append(client.getServiceid());
|
||||
sb.append(", serviceversion = ").append(client.getServiceversion());
|
||||
sb.append(", action.size = ").append(client.getActionCount());
|
||||
sb.append(", address = ").append(clientAddress).append(", groups = ").append(transport == null ? null : transport.getName());
|
||||
sb.append(", remotes = ").append(transport == null ? null : Arrays.asList(transport.getRemoteAddresses()));
|
||||
|
||||
@@ -43,10 +43,6 @@ public final class SncpClient {
|
||||
|
||||
protected final Attribute[] paramAttrs; // 为null表示无DynCall处理,index=0固定为null, 其他为参数标记的DynCall回调方法
|
||||
|
||||
protected final int handlerFuncParamIndex;
|
||||
|
||||
protected final int handlerAttachParamIndex;
|
||||
|
||||
protected final int addressTargetParamIndex;
|
||||
|
||||
protected final int addressSourceParamIndex;
|
||||
@@ -64,26 +60,18 @@ public final class SncpClient {
|
||||
Annotation[][] anns = method.getParameterAnnotations();
|
||||
int targetAddrIndex = -1;
|
||||
int sourceAddrIndex = -1;
|
||||
int handlerAttachIndex = -1;
|
||||
int handlerFuncIndex = -1;
|
||||
|
||||
boolean hasattr = false;
|
||||
Attribute[] atts = new Attribute[paramTypes.length + 1];
|
||||
if (anns.length > 0) {
|
||||
Class<?>[] params = method.getParameterTypes();
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (CompletionHandler.class.isAssignableFrom(params[i])) {
|
||||
handlerFuncIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < anns.length; i++) {
|
||||
if (anns[i].length > 0) {
|
||||
for (Annotation ann : anns[i]) {
|
||||
if (ann.annotationType() == DynAttachment.class) {
|
||||
handlerAttachIndex = i;
|
||||
} else if (ann.annotationType() == DynTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
if (ann.annotationType() == RpcTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
targetAddrIndex = i;
|
||||
} else if (ann.annotationType() == DynSourceAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
} else if (ann.annotationType() == RpcSourceAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
|
||||
sourceAddrIndex = i;
|
||||
}
|
||||
}
|
||||
@@ -103,10 +91,7 @@ public final class SncpClient {
|
||||
}
|
||||
this.addressTargetParamIndex = targetAddrIndex;
|
||||
this.addressSourceParamIndex = sourceAddrIndex;
|
||||
this.handlerFuncParamIndex = handlerFuncIndex;
|
||||
this.handlerAttachParamIndex = handlerAttachIndex;
|
||||
this.paramAttrs = hasattr ? atts : null;
|
||||
if (this.handlerFuncParamIndex >= 0 && method.getReturnType() != void.class) throw new RuntimeException(method + " has CompletionHandler type parameter but return type is not void");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,7 +104,7 @@ public final class SncpClient {
|
||||
|
||||
protected final boolean finest = logger.isLoggable(Level.FINEST);
|
||||
|
||||
protected final JsonConvert jsonConvert = JsonFactory.root().getConvert();
|
||||
protected final JsonConvert convert = JsonFactory.root().getConvert();
|
||||
|
||||
protected final String name;
|
||||
|
||||
@@ -135,15 +120,18 @@ public final class SncpClient {
|
||||
|
||||
protected final DLong serviceid;
|
||||
|
||||
protected final int serviceversion;
|
||||
|
||||
protected final SncpAction[] actions;
|
||||
|
||||
protected final Consumer<Runnable> executor;
|
||||
|
||||
public <T extends Service> SncpClient(final String serviceName, final Class<T> serviceType, final Consumer<Runnable> executor,
|
||||
public <T extends Service> SncpClient(final String serviceName, final Class<T> serviceType, final T service, final Consumer<Runnable> executor,
|
||||
final boolean remote, final Class serviceClass, final InetSocketAddress clientAddress) {
|
||||
this.remote = remote;
|
||||
this.executor = executor;
|
||||
this.serviceClass = serviceClass;
|
||||
this.serviceversion = service.version();
|
||||
this.clientAddress = clientAddress;
|
||||
this.name = serviceName;
|
||||
this.serviceid = Sncp.hash(serviceType.getName() + ':' + serviceName);
|
||||
@@ -157,6 +145,15 @@ public final class SncpClient {
|
||||
this.addrPort = clientAddress == null ? 0 : clientAddress.getPort();
|
||||
}
|
||||
|
||||
static List<SncpAction> getSncpActions(final Class serviceClass) {
|
||||
final List<SncpAction> actions = new ArrayList<>();
|
||||
//------------------------------------------------------------------------------
|
||||
for (java.lang.reflect.Method method : parseMethod(serviceClass)) {
|
||||
actions.add(new SncpAction(method, Sncp.hash(method)));
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
public InetSocketAddress getClientAddress() {
|
||||
return clientAddress;
|
||||
}
|
||||
@@ -165,6 +162,10 @@ public final class SncpClient {
|
||||
return serviceid;
|
||||
}
|
||||
|
||||
public int getServiceversion() {
|
||||
return serviceversion;
|
||||
}
|
||||
|
||||
public int getActionCount() {
|
||||
return actions.length;
|
||||
}
|
||||
@@ -173,7 +174,7 @@ public final class SncpClient {
|
||||
public String toString() {
|
||||
String service = serviceClass.getName();
|
||||
if (remote) service = service.replace(Sncp.LOCALPREFIX, Sncp.REMOTEPREFIX);
|
||||
return this.getClass().getSimpleName() + "(service = " + service + ", serviceid = " + serviceid + ", name = '" + name
|
||||
return this.getClass().getSimpleName() + "(service = " + service + ", serviceid = " + serviceid + ", serviceversion = " + serviceversion + ", name = '" + name
|
||||
+ "', address = " + (clientAddress == null ? "" : (clientAddress.getHostString() + ":" + clientAddress.getPort()))
|
||||
+ ", actions.size = " + actions.length + ")";
|
||||
}
|
||||
@@ -192,6 +193,7 @@ public final class SncpClient {
|
||||
if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue;
|
||||
if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue;
|
||||
if (method.getName().equals("init") || method.getName().equals("destroy")) continue;
|
||||
if (method.getName().equals("version") || method.getName().equals("name")) continue;
|
||||
//if (onlySncpDyn && method.getAnnotation(SncpDyn.class) == null) continue;
|
||||
DLong actionid = Sncp.hash(method);
|
||||
Method old = actionids.get(actionid);
|
||||
@@ -218,83 +220,90 @@ public final class SncpClient {
|
||||
return multis;
|
||||
}
|
||||
|
||||
public void remoteSameGroup(final BsonConvert convert, 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];
|
||||
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler,因为之前本地方法已经调用过了
|
||||
for (InetSocketAddress addr : transport.getRemoteAddresses()) {
|
||||
remote0(null, convert, transport, addr, action, params);
|
||||
remote0(bsonConvert, jsonConvert, transport, addr, action, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void asyncRemoteSameGroup(final BsonConvert convert, Transport transport, final int index, final Object... params) {
|
||||
public void asyncRemoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
|
||||
if (executor != null) {
|
||||
executor.accept(() -> {
|
||||
remoteSameGroup(convert, transport, index, params);
|
||||
remoteSameGroup(bsonConvert, jsonConvert, transport, index, params);
|
||||
});
|
||||
} else {
|
||||
remoteSameGroup(convert, transport, index, params);
|
||||
remoteSameGroup(bsonConvert, jsonConvert, transport, index, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void remoteDiffGroup(final BsonConvert convert, 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;
|
||||
final SncpAction action = actions[index];
|
||||
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler,因为之前本地方法已经调用过了
|
||||
for (Transport transport : transports) {
|
||||
remote0(null, convert, transport, null, action, params);
|
||||
remote0(bsonConvert, jsonConvert, transport, null, action, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void asyncRemoteDiffGroup(final BsonConvert convert, Transport[] transports, final int index, final Object... params) {
|
||||
public void asyncRemoteDiffGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport[] transports, final int index, final Object... params) {
|
||||
if (transports == null || transports.length < 1) return;
|
||||
if (executor != null) {
|
||||
executor.accept(() -> {
|
||||
remoteDiffGroup(convert, transports, index, params);
|
||||
remoteDiffGroup(bsonConvert, jsonConvert, transports, index, params);
|
||||
});
|
||||
} else {
|
||||
remoteDiffGroup(convert, transports, index, params);
|
||||
remoteDiffGroup(bsonConvert, jsonConvert, transports, index, params);
|
||||
}
|
||||
}
|
||||
|
||||
//只给远程模式调用的
|
||||
public <T> T remote(final BsonConvert convert, 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 CompletionHandler handlerFunc = action.handlerFuncParamIndex >= 0 ? (CompletionHandler) params[action.handlerFuncParamIndex] : null;
|
||||
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null;
|
||||
Future<byte[]> future = remote0(handlerFunc, convert, transport, null, action, params);
|
||||
if (handlerFunc != null) return null;
|
||||
final BsonReader reader = convert.pollBsonReader();
|
||||
SncpFuture<byte[]> future = remote0(bsonConvert, jsonConvert, transport, null, action, params);
|
||||
|
||||
final BsonReader reader = bsonConvert.pollBsonReader();
|
||||
try {
|
||||
reader.setBytes(future.get(5, TimeUnit.SECONDS));
|
||||
byte i;
|
||||
while ((i = reader.readByte()) != 0) {
|
||||
final Attribute attr = action.paramAttrs[i];
|
||||
attr.set(params[i - 1], convert.convertFrom(attr.type(), reader));
|
||||
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
|
||||
}
|
||||
return convert.convertFrom(action.resultTypes, reader);
|
||||
return bsonConvert.convertFrom(action.resultTypes, reader);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
logger.log(Level.SEVERE, actions[index].method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote error", e);
|
||||
throw new RuntimeException(actions[index].method + " sncp remote error", e);
|
||||
} finally {
|
||||
convert.offerBsonReader(reader);
|
||||
bsonConvert.offerBsonReader(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void remote(final BsonConvert convert, Transport[] transports, final int index, final Object... params) {
|
||||
public <T> void remote(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport[] transports, final int index, final Object... params) {
|
||||
if (transports == null || transports.length < 1) return;
|
||||
remote(convert, transports[0], index, params);
|
||||
remote(bsonConvert, jsonConvert, transports[0], index, params);
|
||||
for (int i = 1; i < transports.length; i++) {
|
||||
remote0(null, convert, transports[i], null, actions[index], params);
|
||||
remote0(bsonConvert, jsonConvert, transports[i], null, actions[index], params);
|
||||
}
|
||||
}
|
||||
|
||||
private Future<byte[]> remote0(final CompletionHandler handler, final BsonConvert convert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
|
||||
private SncpFuture<byte[]> remote0(final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
|
||||
if ("rest".equalsIgnoreCase(transport.getKind())) {
|
||||
return remoteRest0(jsonConvert, transport, addr0, action, params);
|
||||
}
|
||||
return remoteSncp0(bsonConvert, transport, addr0, action, params);
|
||||
}
|
||||
|
||||
private SncpFuture<byte[]> remoteRest0(final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private SncpFuture<byte[]> remoteSncp0(final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
|
||||
Type[] myparamtypes = action.paramTypes;
|
||||
if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.clientAddress;
|
||||
final BsonWriter writer = convert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
|
||||
final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
|
||||
writer.writeTo(DEFAULT_HEADER);
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
convert.convertTo(writer, myparamtypes[i], params[i]);
|
||||
bsonConvert.convertTo(writer, myparamtypes[i], params[i]);
|
||||
}
|
||||
final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度
|
||||
final long seqid = System.nanoTime();
|
||||
@@ -302,14 +311,14 @@ public final class SncpClient {
|
||||
final SocketAddress addr = addr0 == null ? (action.addressTargetParamIndex >= 0 ? (SocketAddress) params[action.addressTargetParamIndex] : null) : addr0;
|
||||
final AsyncConnection conn = transport.pollConnection(addr);
|
||||
if (conn == null || !conn.isOpen()) {
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + jsonConvert.convertTo(params) + ") cannot connect " + (conn == null ? addr : conn.getRemoteAddress()));
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") cannot connect " + (conn == null ? addr : conn.getRemoteAddress()));
|
||||
throw new RuntimeException("sncp " + (conn == null ? addr : conn.getRemoteAddress()) + " cannot connect");
|
||||
}
|
||||
final ByteBuffer[] sendBuffers = writer.toBuffers();
|
||||
fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength);
|
||||
|
||||
final ByteBuffer buffer = transport.pollBuffer();
|
||||
final SncpFuture<byte[]> future = new SncpFuture();
|
||||
final SncpFuture<byte[]> future = new SncpFuture(false);
|
||||
conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() {
|
||||
|
||||
@Override
|
||||
@@ -370,7 +379,7 @@ public final class SncpClient {
|
||||
final int respBodyLength = buffer.getInt();
|
||||
final int retcode = buffer.getInt();
|
||||
if (retcode != 0) {
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + jsonConvert.convertTo(params) + ") deal error (retcode=" + retcode + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")");
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") deal error (retcode=" + retcode + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")");
|
||||
throw new RuntimeException("remote service(" + action.method + ") deal error (retcode=" + retcode + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")");
|
||||
}
|
||||
|
||||
@@ -391,43 +400,21 @@ public final class SncpClient {
|
||||
future.set(this.body);
|
||||
transport.offerBuffer(buffer);
|
||||
transport.offerConnection(false, conn);
|
||||
if (handler != null) {
|
||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||
final BsonReader reader = convert.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], convert.convertFrom(attr.type(), reader));
|
||||
}
|
||||
Object rs = convert.convertFrom(action.resultTypes, reader);
|
||||
handler.completed(rs, handlerAttach);
|
||||
} catch (Exception e) {
|
||||
handler.failed(e, handlerAttach);
|
||||
} finally {
|
||||
convert.offerBsonReader(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Void attachment2) {
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote read exec failed", exc);
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote read exec failed", exc);
|
||||
future.set(new RuntimeException(action.method + " sncp remote exec failed"));
|
||||
transport.offerBuffer(buffer);
|
||||
transport.offerConnection(true, conn);
|
||||
if (handler != null) {
|
||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||
handler.failed(exc, handlerAttach);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, ByteBuffer[] attachment) {
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote write exec failed", exc);
|
||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote write exec failed", exc);
|
||||
transport.offerBuffer(buffer);
|
||||
transport.offerConnection(true, conn);
|
||||
}
|
||||
@@ -440,7 +427,9 @@ public final class SncpClient {
|
||||
if (rseqid != seqid) throw new RuntimeException("sncp(" + action.method + ") response.seqid = " + seqid + ", but request.seqid =" + rseqid);
|
||||
if (buffer.getChar() != HEADER_SIZE) throw new RuntimeException("sncp(" + action.method + ") buffer receive header.length not " + HEADER_SIZE);
|
||||
DLong rserviceid = DLong.read(buffer);
|
||||
if (!rserviceid.equals(serviceid)) throw new RuntimeException("sncp(" + action.method + ") response.serviceid = " + serviceid + ", but request.serviceid =" + rserviceid);
|
||||
if (!rserviceid.equals(this.serviceid)) throw new RuntimeException("sncp(" + action.method + ") response.serviceid = " + serviceid + ", but request.serviceid =" + rserviceid);
|
||||
int version = buffer.getInt();
|
||||
if (version != this.serviceversion) throw new RuntimeException("sncp(" + action.method + ") response.serviceversion = " + serviceversion + ", but request.serviceversion =" + version);
|
||||
DLong raction = DLong.read(buffer);
|
||||
if (!action.actionid.equals(raction)) throw new RuntimeException("sncp(" + action.method + ") response.actionid = " + action.actionid + ", but request.actionid =(" + raction + ")");
|
||||
buffer.getInt(); //地址
|
||||
@@ -454,6 +443,7 @@ public final class SncpClient {
|
||||
buffer.putLong(seqid); //序列号
|
||||
buffer.putChar((char) HEADER_SIZE); //header长度
|
||||
DLong.write(buffer, this.serviceid);
|
||||
buffer.putInt(this.serviceversion);
|
||||
DLong.write(buffer, actionid);
|
||||
buffer.put(addrBytes);
|
||||
buffer.putChar((char) this.addrPort);
|
||||
@@ -470,14 +460,22 @@ public final class SncpClient {
|
||||
|
||||
private RuntimeException ex;
|
||||
|
||||
public SncpFuture() {
|
||||
private final boolean rest;
|
||||
|
||||
public SncpFuture(boolean rest) {
|
||||
this.rest = rest;
|
||||
}
|
||||
|
||||
public SncpFuture(T result) {
|
||||
public SncpFuture(boolean rest, T result) {
|
||||
this.rest = rest;
|
||||
this.result = result;
|
||||
this.done = true;
|
||||
}
|
||||
|
||||
public boolean isRest() {
|
||||
return this.rest;
|
||||
}
|
||||
|
||||
public void set(T result) {
|
||||
this.result = result;
|
||||
this.done = true;
|
||||
|
||||
@@ -62,7 +62,8 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
if (method.getName().equals("getClass") || method.getName().equals("toString")) continue;
|
||||
if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue;
|
||||
if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue;
|
||||
if (method.getName().equals("init") || method.getName().equals("destroy") || method.getName().equals("name")) continue;
|
||||
if (method.getName().equals("init") || method.getName().equals("destroy")) continue;
|
||||
if (method.getName().equals("version") || method.getName().equals("name")) continue;
|
||||
final DLong actionid = Sncp.hash(method);
|
||||
SncpServletAction action = SncpServletAction.create(service, actionid, method);
|
||||
action.convert = convert;
|
||||
@@ -146,7 +147,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
|
||||
public abstract void action(final BsonReader in, final BsonWriter out) throws Throwable;
|
||||
|
||||
public final void callParameter(final BsonWriter out, final Object... params) {
|
||||
public final void _callParameter(final BsonWriter out, final Object... params) {
|
||||
if (paramAttrs != null) {
|
||||
for (int i = 1; i < paramAttrs.length; i++) {
|
||||
org.redkale.util.Attribute attr = paramAttrs[i];
|
||||
@@ -176,7 +177,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||
* Object rs = service.change(arg1, arg2, arg3);
|
||||
* callParameter(out, arg1, arg2, arg3);
|
||||
* _callParameter(out, arg1, arg2, arg3);
|
||||
* convert.convertTo(out, paramTypes[0], rs);
|
||||
* }
|
||||
* }
|
||||
@@ -317,7 +318,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
mv.visitVarInsn(ASTORE, store); //11
|
||||
}
|
||||
//------------------------- callParameter 方法 --------------------------------
|
||||
//------------------------- _callParameter 方法 --------------------------------
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
if (paramClasses.length <= 5) { //参数总数量
|
||||
@@ -353,7 +354,7 @@ public final class SncpDynServlet extends SncpServlet {
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false);
|
||||
|
||||
//-------------------------直接返回 或者 调用convertTo方法 --------------------------------
|
||||
int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1;
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.redkale.util.*;
|
||||
*/
|
||||
public final class SncpRequest extends Request<SncpContext> {
|
||||
|
||||
public static final int HEADER_SIZE = 56;
|
||||
public static final int HEADER_SIZE = 60;
|
||||
|
||||
public static final byte[] DEFAULT_HEADER = new byte[HEADER_SIZE];
|
||||
|
||||
@@ -28,6 +28,8 @@ public final class SncpRequest extends Request<SncpContext> {
|
||||
|
||||
private long seqid;
|
||||
|
||||
private int serviceversion;
|
||||
|
||||
private DLong serviceid;
|
||||
|
||||
private DLong actionid;
|
||||
@@ -60,6 +62,7 @@ public final class SncpRequest extends Request<SncpContext> {
|
||||
return -1;
|
||||
}
|
||||
this.serviceid = DLong.read(buffer);
|
||||
this.serviceversion = buffer.getInt();
|
||||
this.actionid = DLong.read(buffer);
|
||||
buffer.get(bufferbytes);
|
||||
this.bodylength = buffer.getInt();
|
||||
@@ -92,15 +95,16 @@ public final class SncpRequest extends Request<SncpContext> {
|
||||
@Override
|
||||
public String toString() {
|
||||
return SncpRequest.class.getSimpleName() + "{seqid=" + this.seqid
|
||||
+ ",serviceid=" + this.serviceid + ",actionid=" + this.actionid
|
||||
+ ",bodylength=" + this.bodylength + ",bodyoffset=" + this.bodyoffset
|
||||
+ ",remoteAddress=" + getRemoteAddress() + "}";
|
||||
+ ",serviceversion=" + this.serviceversion + ",serviceid=" + this.serviceid
|
||||
+ ",actionid=" + this.actionid + ",bodylength=" + this.bodylength
|
||||
+ ",bodyoffset=" + this.bodyoffset + ",remoteAddress=" + getRemoteAddress() + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void recycle() {
|
||||
this.seqid = 0;
|
||||
this.serviceid = null;
|
||||
this.serviceversion = 0;
|
||||
this.actionid = null;
|
||||
this.bodylength = 0;
|
||||
this.bodyoffset = 0;
|
||||
@@ -122,6 +126,10 @@ public final class SncpRequest extends Request<SncpContext> {
|
||||
return seqid;
|
||||
}
|
||||
|
||||
public int getServiceversion() {
|
||||
return serviceversion;
|
||||
}
|
||||
|
||||
public DLong getServiceid() {
|
||||
return serviceid;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ public final class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
|
||||
public static final int RETCODE_ILLSERVICEID = (1 << 10); //无效serviceid
|
||||
|
||||
public static final int RETCODE_ILLACTIONID = (1 << 11); //无效actionid
|
||||
public static final int RETCODE_ILLSERVICEVER = (1 << 11); //无效serviceversion
|
||||
|
||||
public static final int RETCODE_ILLACTIONID = (1 << 15); //无效actionid
|
||||
|
||||
public static final int RETCODE_THROWEXCEPTION = (1 << 30); //内部异常
|
||||
|
||||
@@ -37,6 +39,7 @@ public final class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
|
||||
public static String getRetCodeInfo(int retcode) {
|
||||
if (retcode == RETCODE_ILLSERVICEID) return "serviceid is invalid";
|
||||
if (retcode == RETCODE_ILLSERVICEVER) return "serviceversion is invalid";
|
||||
if (retcode == RETCODE_ILLACTIONID) return "actionid is invalid";
|
||||
if (retcode == RETCODE_THROWEXCEPTION) return "Inner exception";
|
||||
return null;
|
||||
@@ -68,6 +71,7 @@ public final class SncpResponse extends Response<SncpContext, SncpRequest> {
|
||||
buffer.putLong(request.getSeqid());
|
||||
buffer.putChar((char) SncpRequest.HEADER_SIZE);
|
||||
DLong.write(buffer, request.getServiceid());
|
||||
buffer.putInt(request.getServiceversion());
|
||||
DLong.write(buffer, request.getActionid());
|
||||
buffer.put(addrBytes);
|
||||
buffer.putChar((char) this.addrPort);
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import org.redkale.convert.bson.*;
|
||||
import org.redkale.net.*;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.util.*;
|
||||
import org.redkale.watch.*;
|
||||
|
||||
@@ -37,13 +38,18 @@ public final class SncpServer extends Server<DLong, SncpContext, SncpRequest, Sn
|
||||
super.init(config);
|
||||
}
|
||||
|
||||
public void addService(ServiceWrapper entry) {
|
||||
public void addSncpServlet(ServiceWrapper entry) {
|
||||
for (Class type : entry.getTypes()) {
|
||||
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), entry.getName(), type, entry.getService());
|
||||
this.prepare.addServlet(sds, null, entry.getConf());
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Service> void addSncpServlet(Class<T> serviceType, String name, T service, AnyValue conf) {
|
||||
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), name, serviceType, service);
|
||||
this.prepare.addServlet(sds, null, conf);
|
||||
}
|
||||
|
||||
public List<SncpServlet> getSncpServlets() {
|
||||
return ((SncpPrepareServlet) this.prepare).getSncpServlets();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ package org.redkale.service;
|
||||
import java.beans.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.*;
|
||||
@@ -26,6 +25,7 @@ import org.redkale.util.*;
|
||||
* @param <V> value类型
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@AutoLoad(false)
|
||||
@@ -191,11 +191,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
return !entry.isExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exists(final CompletionHandler<Boolean, K> handler, @DynAttachment final K key) {
|
||||
if (handler != null) handler.completed(exists(key), key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
if (key == null) return null;
|
||||
@@ -206,11 +201,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
return (V) entry.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void get(final CompletionHandler<V, K> handler, @DynAttachment final K key) {
|
||||
if (handler != null) handler.completed(get(key), key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public V getAndRefresh(K key, final int expireSeconds) {
|
||||
@@ -224,12 +214,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
return (V) entry.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAndRefresh(final CompletionHandler<V, K> handler, @DynAttachment final K key, final int expireSeconds) {
|
||||
V rs = getAndRefresh(key, expireSeconds);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void refresh(K key, final int expireSeconds) {
|
||||
@@ -240,12 +224,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
entry.expireSeconds = expireSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(final CompletionHandler<Void, K> handler, final K key, final int expireSeconds) {
|
||||
refresh(key, expireSeconds);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void set(K key, V value) {
|
||||
@@ -261,12 +239,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final CompletionHandler<Void, K> handler, @DynAttachment final K key, final V value) {
|
||||
set(key, value);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void set(int expireSeconds, K key, V value) {
|
||||
@@ -282,12 +254,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final CompletionHandler<Void, K> handler, final int expireSeconds, @DynAttachment final K key, final V value) {
|
||||
set(expireSeconds, key, value);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void setExpireSeconds(K key, int expireSeconds) {
|
||||
@@ -297,12 +263,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
entry.expireSeconds = expireSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpireSeconds(final CompletionHandler<Void, K> handler, @DynAttachment final K key, final int expireSeconds) {
|
||||
setExpireSeconds(key, expireSeconds);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void remove(K key) {
|
||||
@@ -310,32 +270,16 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
container.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(final CompletionHandler<Void, K> handler, @DynAttachment final K key) {
|
||||
remove(key);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getCollection(final K key) {
|
||||
return (Collection<V>) get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCollection(final CompletionHandler<Collection<V>, K> handler, @DynAttachment final K key) {
|
||||
if (handler != null) handler.completed(getCollection(key), key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getCollectionAndRefresh(final K key, final int expireSeconds) {
|
||||
return (Collection<V>) getAndRefresh(key, expireSeconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCollectionAndRefresh(final CompletionHandler<Collection<V>, K> handler, @DynAttachment final K key, final int expireSeconds) {
|
||||
if (handler != null) handler.completed(getCollectionAndRefresh(key, expireSeconds), key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void appendListItem(K key, V value) {
|
||||
@@ -352,12 +296,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendListItem(final CompletionHandler<Void, K> handler, @DynAttachment final K key, final V value) {
|
||||
appendListItem(key, value);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void removeListItem(K key, V value) {
|
||||
@@ -367,12 +305,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
((Collection) entry.getValue()).remove(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListItem(final CompletionHandler<Void, K> handler, @DynAttachment final K key, final V value) {
|
||||
removeListItem(key, value);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void appendSetItem(K key, V value) {
|
||||
@@ -389,12 +321,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendSetItem(final CompletionHandler<Void, K> handler, @DynAttachment final K key, final V value) {
|
||||
appendSetItem(key, value);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiRun
|
||||
public void removeSetItem(K key, V value) {
|
||||
@@ -404,12 +330,6 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
|
||||
((Set) entry.getValue()).remove(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSetItem(final CompletionHandler<Void, K> handler, @DynAttachment final K key, final V value) {
|
||||
removeSetItem(key, value);
|
||||
if (handler != null) handler.completed(null, key);
|
||||
}
|
||||
|
||||
public static enum CacheEntryType {
|
||||
OBJECT, SET, LIST;
|
||||
}
|
||||
|
||||
@@ -1,128 +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.service;
|
||||
|
||||
import org.redkale.source.DataSQLListener;
|
||||
import org.redkale.source.DataSource;
|
||||
import org.redkale.source.DataDefaultSource;
|
||||
import org.redkale.util.AnyValue;
|
||||
import org.redkale.util.AutoLoad;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.*;
|
||||
import javax.annotation.Resource;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* 暂时不实现
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Deprecated
|
||||
@AutoLoad(false)
|
||||
@ResourceType({DataSQLListenerService.class, DataSQLListener.class})
|
||||
public class DataSQLListenerService implements DataSQLListener, Service {
|
||||
|
||||
private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL";
|
||||
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
private final boolean finest = logger.isLoggable(Level.FINEST);
|
||||
|
||||
@Resource(name = "APP_HOME")
|
||||
private File home;
|
||||
|
||||
@Resource(name = "$")
|
||||
private DataSource source;
|
||||
|
||||
private final BlockingQueue<String> queue = new ArrayBlockingQueue<>(1024 * 1024);
|
||||
|
||||
private PrintStream syncfile;
|
||||
|
||||
@Override
|
||||
public void init(AnyValue config) {
|
||||
new Thread() {
|
||||
{
|
||||
setName(DataSQLListener.class.getSimpleName() + "-Thread");
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
String sql = queue.take();
|
||||
send(sql);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, this.getName() + " occur error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return this.getClass().getAnnotation(Resource.class).name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(AnyValue config) {
|
||||
if (syncfile != null) syncfile.close();
|
||||
}
|
||||
|
||||
private void write(String... sqls) {
|
||||
try {
|
||||
if (syncfile == null) {
|
||||
File root = new File(home, "dbsync");
|
||||
root.mkdirs();
|
||||
syncfile = new PrintStream(new FileOutputStream(new File(root, "sql-" + name() + ".sql"), true), false, "UTF-8");
|
||||
}
|
||||
for (String sql : sqls) {
|
||||
syncfile.print(sql + ";\r\n");
|
||||
}
|
||||
syncfile.flush();
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "write sql file error. (" + name() + ", " + Arrays.toString(sqls) + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(String... sqls) {
|
||||
put(sqls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String... sqls) {
|
||||
put(sqls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String... sqls) {
|
||||
put(sqls);
|
||||
}
|
||||
|
||||
private void put(String... sqls) {
|
||||
String date = String.format(format, System.currentTimeMillis());
|
||||
for (String sql : sqls) {
|
||||
try {
|
||||
queue.put("/* " + date + " */ " + sql);
|
||||
} catch (Exception e) {
|
||||
write(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MultiRun(selfrun = false, async = true)
|
||||
public void send(String... sqls) {
|
||||
((DataDefaultSource) source).directExecute(sqls);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.redkale.service;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
@@ -34,163 +33,89 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
|
||||
source.insert(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void insert(final CompletionHandler<Void, T[]> handler, @DynAttachment @DynCall(DataCallArrayAttribute.class) final T... values) {
|
||||
source.insert(values);
|
||||
if (handler != null) handler.completed(null, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(T... values) {
|
||||
source.delete(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final CompletionHandler<Void, T[]> handler, @DynAttachment final T... values) {
|
||||
source.delete(values);
|
||||
if (handler != null) handler.completed(null, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final Class<T> clazz, final Serializable... ids) {
|
||||
source.delete(clazz, ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final CompletionHandler<Void, Serializable[]> handler, final Class<T> clazz, @DynAttachment final Serializable... ids) {
|
||||
source.delete(clazz, ids);
|
||||
if (handler != null) handler.completed(null, ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final Class<T> clazz, FilterNode node) {
|
||||
source.delete(clazz, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final CompletionHandler<Void, FilterNode> handler, final Class<T> clazz, @DynAttachment final FilterNode node) {
|
||||
source.delete(clazz, node);
|
||||
if (handler != null) handler.completed(null, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void update(T... values) {
|
||||
source.update(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void update(final CompletionHandler<Void, T[]> handler, @DynAttachment final T... values) {
|
||||
source.update(values);
|
||||
if (handler != null) handler.completed(null, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value) {
|
||||
source.updateColumn(clazz, id, column, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, @DynAttachment final Serializable id, final String column, final Serializable value) {
|
||||
source.updateColumn(clazz, id, column, value);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node) {
|
||||
source.updateColumn(clazz, column, value, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final CompletionHandler<Void, FilterNode> handler, final Class<T> clazz, final String column, final Serializable value, @DynAttachment final FilterNode node) {
|
||||
source.updateColumn(clazz, column, value, node);
|
||||
if (handler != null) handler.completed(null, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnIncrement(final Class<T> clazz, final Serializable id, final String column, long incvalue) {
|
||||
source.updateColumnIncrement(clazz, id, column, incvalue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnIncrement(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, @DynAttachment final Serializable id, final String column, long incvalue) {
|
||||
source.updateColumnIncrement(clazz, id, column, incvalue);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnAnd(final Class<T> clazz, final Serializable id, final String column, long incvalue) {
|
||||
source.updateColumnAnd(clazz, id, column, incvalue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnAnd(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, @DynAttachment final Serializable id, final String column, long incvalue) {
|
||||
source.updateColumnAnd(clazz, id, column, incvalue);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnOr(final Class<T> clazz, final Serializable id, final String column, long incvalue) {
|
||||
source.updateColumnOr(clazz, id, column, incvalue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnOr(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, @DynAttachment final Serializable id, final String column, long incvalue) {
|
||||
source.updateColumnOr(clazz, id, column, incvalue);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumns(T bean, final String... columns) {
|
||||
source.updateColumns(bean, columns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumns(final CompletionHandler<Void, T> handler, @DynAttachment final T bean, final String... columns) {
|
||||
source.updateColumns(bean, columns);
|
||||
if (handler != null) handler.completed(null, bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumns(T bean, final FilterNode node, final String... columns) {
|
||||
source.updateColumns(bean, node, columns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumns(final CompletionHandler<Void, FilterNode> handler, final T bean, @DynAttachment final FilterNode node, final String... columns) {
|
||||
source.updateColumns(bean, node, columns);
|
||||
if (handler != null) handler.completed(null, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, FilterFunc func, final String column) {
|
||||
return source.getNumberResult(entityClass, func, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNumberResult(final CompletionHandler<Number, String> handler, final Class entityClass, final FilterFunc func, @DynAttachment final String column) {
|
||||
Number rs = source.getNumberResult(entityClass, func, column);
|
||||
if (handler != null) handler.completed(rs, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterBean bean) {
|
||||
return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void getNumberResult(final CompletionHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) {
|
||||
getNumberResult(handler, entityClass, func, column, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterNode node) {
|
||||
return source.getNumberResult(entityClass, func, column, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNumberResult(final CompletionHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, @DynAttachment final FilterNode node) {
|
||||
Number rs = source.getNumberResult(entityClass, func, column, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column) {
|
||||
return source.getNumberResult(entityClass, func, defVal, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterNode node) {
|
||||
return source.getNumberResult(entityClass, func, defVal, column, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,373 +123,176 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
|
||||
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, String> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, @DynAttachment final String funcColumn) {
|
||||
Map<K, N> map = source.queryColumnMap(entityClass, keyColumn, func, funcColumn);
|
||||
if (handler != null) handler.completed(map, funcColumn);
|
||||
}
|
||||
|
||||
@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) {
|
||||
return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, FilterNode> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) {
|
||||
queryColumnMap(handler, entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@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) {
|
||||
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, FilterNode> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, @DynAttachment final FilterNode node) {
|
||||
Map<K, N> map = source.queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
|
||||
if (handler != null) handler.completed(map, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final Serializable pk) {
|
||||
return source.find(clazz, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, @DynAttachment final Serializable pk) {
|
||||
T rs = source.find(clazz, pk);
|
||||
if (handler != null) handler.completed(rs, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, SelectColumn selects, final Serializable pk) {
|
||||
return source.find(clazz, selects, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final SelectColumn selects, @DynAttachment final Serializable pk) {
|
||||
T rs = source.find(clazz, selects, pk);
|
||||
if (handler != null) handler.completed(rs, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final String column, final Serializable key) {
|
||||
return source.find(clazz, column, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final String column, @DynAttachment final Serializable key) {
|
||||
T rs = source.find(clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T find(final Class<T> clazz, FilterBean bean) {
|
||||
return find(clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final FilterBean bean) {
|
||||
find(handler, clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, FilterNode node) {
|
||||
return source.find(clazz, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, @DynAttachment final FilterNode node) {
|
||||
T rs = source.find(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T find(final Class<T> clazz, final SelectColumn selects, FilterBean bean) {
|
||||
return find(clazz, selects, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
|
||||
find(handler, clazz, selects, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
|
||||
return source.find(clazz, selects, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, @DynAttachment final FilterNode node) {
|
||||
T rs = source.find(clazz, selects, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean exists(final Class<T> clazz, final Serializable pk) {
|
||||
return source.exists(clazz, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void exists(final CompletionHandler<Boolean, Serializable> handler, final Class<T> clazz, @DynAttachment final Serializable pk) {
|
||||
boolean rs = source.exists(clazz, pk);
|
||||
if (handler != null) handler.completed(rs, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> boolean exists(final Class<T> clazz, FilterBean bean) {
|
||||
return exists(clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void exists(final CompletionHandler<Boolean, FilterNode> handler, final Class<T> clazz, final FilterBean bean) {
|
||||
exists(handler, clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean exists(final Class<T> clazz, FilterNode node) {
|
||||
return source.exists(clazz, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void exists(final CompletionHandler<Boolean, FilterNode> handler, final Class<T> clazz, @DynAttachment final FilterNode node) {
|
||||
boolean rs = source.exists(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, @DynAttachment final Serializable key) {
|
||||
HashSet<V> rs = source.queryColumnSet(selectedColumn, clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterBean bean) {
|
||||
return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterBean bean) {
|
||||
queryColumnSet(handler, selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterNode node) {
|
||||
return source.queryColumnSet(selectedColumn, clazz, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, @DynAttachment final FilterNode node) {
|
||||
HashSet<V> rs = source.queryColumnSet(selectedColumn, clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, @DynAttachment final Serializable key) {
|
||||
List<V> rs = source.queryColumnList(selectedColumn, clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterBean bean) {
|
||||
return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, @DynAttachment final FilterBean bean) {
|
||||
queryColumnList(handler, selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterNode node) {
|
||||
return source.queryColumnList(selectedColumn, clazz, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, @DynAttachment final FilterNode node) {
|
||||
List<V> rs = source.queryColumnList(selectedColumn, clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, V extends Serializable> void queryColumnSheet(final CompletionHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
queryColumnSheet(handler, selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) {
|
||||
return source.queryColumnSheet(selectedColumn, clazz, flipper, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSheet(final CompletionHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, @DynAttachment final FilterNode node) {
|
||||
Sheet<V> rs = source.queryColumnSheet(selectedColumn, clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key) {
|
||||
return source.queryList(clazz, column, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, Serializable> handler, final Class<T> clazz, final String column, @DynAttachment final Serializable key) {
|
||||
List<T> rs = source.queryList(clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> List<T> queryList(final Class<T> clazz, final FilterBean bean) {
|
||||
return queryList(clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final FilterBean bean) {
|
||||
queryList(handler, clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final FilterNode node) {
|
||||
return source.queryList(clazz, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, @DynAttachment final FilterNode node) {
|
||||
List<T> rs = source.queryList(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
|
||||
return queryList(clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
|
||||
queryList(handler, clazz, selects, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
|
||||
return source.queryList(clazz, selects, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, @DynAttachment final FilterNode node) {
|
||||
List<T> rs = source.queryList(clazz, selects, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, Serializable> handler, final Class<T> clazz, final Flipper flipper, final String column, @DynAttachment final Serializable key) {
|
||||
List<T> rs = source.queryList(clazz, flipper, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
return queryList(clazz, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
queryList(handler, clazz, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
return source.queryList(clazz, flipper, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @DynAttachment final FilterNode node) {
|
||||
List<T> rs = source.queryList(clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, SelectColumn selects, final Flipper flipper, final FilterBean bean) {
|
||||
queryList(handler, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, SelectColumn selects, final Flipper flipper, @DynAttachment final FilterNode node) {
|
||||
List<T> rs = source.queryList(clazz, selects, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
return querySheet(clazz, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
querySheet(handler, clazz, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
return source.querySheet(clazz, flipper, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @DynAttachment final FilterNode node) {
|
||||
Sheet<T> rs = source.querySheet(clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
|
||||
querySheet(handler, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @DynAttachment final FilterNode node) {
|
||||
Sheet<T> rs = source.querySheet(clazz, selects, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
source.getClass().getMethod("close").invoke(source);
|
||||
|
||||
@@ -13,7 +13,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
* 本地模式注解。
|
||||
* 声明为LocalService的Service只能以本地模式存在, 即使配置文件中配置成远程模式也将被忽略。
|
||||
*
|
||||
* <p> 详情见: http://redkale.org
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@@ -22,4 +24,5 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
@Retention(RUNTIME)
|
||||
public @interface LocalService {
|
||||
|
||||
String comment() default ""; //备注描述
|
||||
}
|
||||
|
||||
@@ -19,6 +19,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
@Documented
|
||||
@Target({FIELD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface DynRemote {
|
||||
public @interface RpcRemote {
|
||||
|
||||
}
|
||||
@@ -20,6 +20,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
@Documented
|
||||
@Target({PARAMETER})
|
||||
@Retention(RUNTIME)
|
||||
public @interface DynSourceAddress {
|
||||
public @interface RpcSourceAddress {
|
||||
|
||||
}
|
||||
@@ -20,6 +20,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
@Documented
|
||||
@Target({PARAMETER})
|
||||
@Retention(RUNTIME)
|
||||
public @interface DynTargetAddress {
|
||||
public @interface RpcTargetAddress {
|
||||
|
||||
}
|
||||
@@ -44,4 +44,14 @@ public interface Service {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Service的接口版本号
|
||||
* <b>注: public方法的参数或返回类型或参数类型内部变更后改值必须进行改变</b>
|
||||
*
|
||||
* @return 接口版本号
|
||||
*/
|
||||
default int version() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getOnlineRemoteAddresses(@DynTargetAddress InetSocketAddress targetAddress, Serializable groupid) {
|
||||
public List<String> getOnlineRemoteAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid) {
|
||||
if (localSncpAddress == null || !localSncpAddress.equals(targetAddress)) return remoteOnlineRemoteAddresses(targetAddress, groupid);
|
||||
final Set<String> engineids = localNodes.get(groupid);
|
||||
if (engineids == null || engineids.isEmpty()) return null;
|
||||
@@ -49,7 +49,7 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendMessage(@DynTargetAddress InetSocketAddress addr, Serializable groupid, boolean recent, Serializable message, boolean last) {
|
||||
public int sendMessage(@RpcTargetAddress InetSocketAddress addr, Serializable groupid, boolean recent, Serializable message, boolean last) {
|
||||
final Set<String> engineids = localNodes.get(groupid);
|
||||
if (engineids == null || engineids.isEmpty()) return RETCODE_GROUP_EMPTY;
|
||||
int code = RETCODE_GROUP_EMPTY;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.redkale.source;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -15,6 +14,7 @@ import java.util.*;
|
||||
* @param <V> value的类型
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public interface CacheSource<K extends Serializable, V extends Object> {
|
||||
@@ -51,36 +51,4 @@ public interface CacheSource<K extends Serializable, V extends Object> {
|
||||
|
||||
public void removeSetItem(final K key, final V value);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public void exists(final CompletionHandler<Boolean, K> handler, final K key);
|
||||
|
||||
public void get(final CompletionHandler<V, K> handler, final K key);
|
||||
|
||||
public void getAndRefresh(final CompletionHandler<V, K> handler, final K key, final int expireSeconds);
|
||||
|
||||
public void refresh(final CompletionHandler<Void, K> handler, final K key, final int expireSeconds);
|
||||
|
||||
public void set(final CompletionHandler<Void, K> handler, final K key, final V value);
|
||||
|
||||
public void set(final CompletionHandler<Void, K> handler, final int expireSeconds, final K key, final V value);
|
||||
|
||||
public void setExpireSeconds(final CompletionHandler<Void, K> handler, final K key, final int expireSeconds);
|
||||
|
||||
public void remove(final CompletionHandler<Void, K> handler, final K key);
|
||||
|
||||
public void getCollection(final CompletionHandler<Collection<V>, K> handler, final K key);
|
||||
|
||||
public void getCollectionAndRefresh(final CompletionHandler<Collection<V>, K> handler, final K key, final int expireSeconds);
|
||||
|
||||
public void appendListItem(final CompletionHandler<Void, K> handler, final K key, final V value);
|
||||
|
||||
public void removeListItem(final CompletionHandler<Void, K> handler, final K key, final V value);
|
||||
|
||||
public void appendSetItem(final CompletionHandler<Void, K> handler, final K key, final V value);
|
||||
|
||||
public void removeSetItem(final CompletionHandler<Void, K> handler, final K key, final V value);
|
||||
|
||||
default void isOpen(final CompletionHandler<Boolean, Void> handler) {
|
||||
if (handler != null) handler.completed(Boolean.TRUE, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class DataCallAttribute implements Attribute<Object, Serializable> {
|
||||
Class cltmp = clazz;
|
||||
do {
|
||||
for (Field field : cltmp.getDeclaredFields()) {
|
||||
if (field.getAnnotation(javax.persistence.Id.class) == null) continue;
|
||||
if (field.getAnnotation(javax.persistence.GeneratedValue.class) == null) continue;
|
||||
try {
|
||||
rs = Attribute.create(cltmp, field);
|
||||
attributes.put(clazz, rs);
|
||||
|
||||
@@ -8,7 +8,6 @@ package org.redkale.source;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -37,6 +36,10 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
|
||||
static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate";
|
||||
|
||||
static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates";
|
||||
|
||||
static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate";
|
||||
|
||||
static final String JDBC_URL = "javax.persistence.jdbc.url";
|
||||
|
||||
static final String JDBC_USER = "javax.persistence.jdbc.user";
|
||||
@@ -66,9 +69,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
@Resource(name = "property.datasource.nodeid")
|
||||
private int nodeid;
|
||||
|
||||
@Resource(name = "$")
|
||||
private DataSQLListener writeListener;
|
||||
|
||||
@Resource(name = "$")
|
||||
private DataCacheListener cacheListener;
|
||||
|
||||
@@ -326,27 +326,19 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void insert(final CompletionHandler<Void, T[]> handler, final T... values) {
|
||||
insert(values);
|
||||
if (handler != null) handler.completed(null, values);
|
||||
}
|
||||
|
||||
private <T> void insert(final Connection conn, final EntityInfo<T> info, T... values) {
|
||||
if (values.length == 0) return;
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
final String sql = info.insertSQL;
|
||||
final PreparedStatement prestmt = info.autoGenerated
|
||||
? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
|
||||
final String sql = info.getInsertSQL(values[0]);
|
||||
final Class primaryType = info.getPrimary().type();
|
||||
final Attribute primary = info.getPrimary();
|
||||
final boolean distributed = info.distributed;
|
||||
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
||||
String[] sqls = null;
|
||||
if (distributed && !info.initedPrimaryValue && primaryType.isPrimitive()) { //由DataSource生成主键
|
||||
synchronized (info) {
|
||||
if (!info.initedPrimaryValue) { //初始化最大主键值
|
||||
try {
|
||||
Statement stmt = conn.createStatement();
|
||||
ResultSet rs = stmt.executeQuery("SELECT MAX(" + info.getPrimarySQLColumn() + ") FROM " + info.getTable(values[0]));
|
||||
if (rs.next()) {
|
||||
@@ -360,48 +352,50 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
rs.close();
|
||||
stmt.close();
|
||||
} catch (SQLException se) {
|
||||
if (info.tableStrategy == null) throw se;
|
||||
}
|
||||
info.initedPrimaryValue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (writeListener == null) {
|
||||
for (final T value : values) {
|
||||
int i = 0;
|
||||
if (distributed) info.createPrimaryValue(value);
|
||||
for (Attribute<T, Serializable> attr : attrs) {
|
||||
prestmt.setObject(++i, attr.get(value));
|
||||
}
|
||||
prestmt.addBatch();
|
||||
}
|
||||
} else { //调用writeListener回调接口
|
||||
char[] sqlchars = sql.toCharArray();
|
||||
sqls = new String[values.length];
|
||||
CharSequence[] ps = new CharSequence[attrs.length];
|
||||
int index = 0;
|
||||
for (final T value : values) {
|
||||
int i = 0;
|
||||
if (distributed) info.createPrimaryValue(value);
|
||||
for (Attribute<T, Serializable> attr : attrs) {
|
||||
Object a = attr.get(value);
|
||||
ps[i] = FilterNode.formatToString(a);
|
||||
prestmt.setObject(++i, a);
|
||||
}
|
||||
prestmt.addBatch();
|
||||
//-----------------------------
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
i = 0;
|
||||
for (char ch : sqlchars) {
|
||||
if (ch == '?') {
|
||||
sb.append(ps[i++]);
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
}
|
||||
sqls[index++] = sb.toString();
|
||||
}
|
||||
}
|
||||
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, values);
|
||||
try {
|
||||
prestmt.executeBatch();
|
||||
if (writeListener != null) writeListener.insert(sqls);
|
||||
} catch (SQLException se) {
|
||||
if (info.tableStrategy == null || !info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) throw se;
|
||||
synchronized (info.tables) {
|
||||
final String oldTable = info.table;
|
||||
final String newTable = info.getTable(values[0]);
|
||||
if (!info.tables.contains(newTable)) {
|
||||
try {
|
||||
Statement st = conn.createStatement();
|
||||
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
|
||||
st.close();
|
||||
info.tables.add(newTable);
|
||||
} catch (SQLException sqle) { //多进程并发时可能会出现重复建表
|
||||
if (newTable.indexOf('.') > 0 && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) {
|
||||
Statement st = conn.createStatement();
|
||||
st.execute("CREATE DATABASE " + newTable.substring(0, newTable.indexOf('.')));
|
||||
st.close();
|
||||
try {
|
||||
st = conn.createStatement();
|
||||
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
|
||||
st.close();
|
||||
info.tables.add(newTable);
|
||||
} catch (SQLException sqle2) {
|
||||
logger.log(Level.SEVERE, "create table2(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle2);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "create table(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
prestmt.close();
|
||||
prestmt = createInsertPreparedStatement(conn, sql, info, values);
|
||||
prestmt.executeBatch();
|
||||
}
|
||||
if (info.autoGenerated) { //由数据库自动生成主键值
|
||||
ResultSet set = prestmt.getGeneratedKeys();
|
||||
int i = -1;
|
||||
@@ -452,6 +446,23 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
private <T> PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
|
||||
final EntityInfo<T> info, T... values) throws SQLException {
|
||||
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
||||
final PreparedStatement prestmt = info.autoGenerated
|
||||
? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
|
||||
|
||||
for (final T value : values) {
|
||||
int i = 0;
|
||||
if (info.distributed || info.autouuid) info.createPrimaryValue(value);
|
||||
for (Attribute<T, Serializable> attr : attrs) {
|
||||
prestmt.setObject(++i, attr.get(value));
|
||||
}
|
||||
prestmt.addBatch();
|
||||
}
|
||||
return prestmt;
|
||||
}
|
||||
|
||||
public <T> void insertCache(Class<T> clazz, T... values) {
|
||||
if (values.length == 0) return;
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
@@ -485,12 +496,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final CompletionHandler<Void, T[]> handler, final T... values) {
|
||||
delete(values);
|
||||
if (handler != null) handler.completed(null, values);
|
||||
}
|
||||
|
||||
private <T> void delete(final Connection conn, final EntityInfo<T> info, T... values) {
|
||||
if (values.length == 0) return;
|
||||
final Attribute primary = info.getPrimary();
|
||||
@@ -517,28 +522,18 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final CompletionHandler<Void, Serializable[]> handler, final Class<T> clazz, final Serializable... ids) {
|
||||
delete(clazz, ids);
|
||||
if (handler != null) handler.completed(null, ids);
|
||||
}
|
||||
|
||||
private <T> void delete(final Connection conn, final EntityInfo<T> info, Serializable... keys) {
|
||||
if (keys.length == 0) return;
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
final Statement stmt = conn.createStatement();
|
||||
String[] sqls = new String[keys.length];
|
||||
int index = -1;
|
||||
for (Serializable key : keys) {
|
||||
String sql = "DELETE FROM " + info.getTable(keys) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(key);
|
||||
sqls[++index] = sql;
|
||||
if (debug.get()) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
|
||||
stmt.addBatch(sql);
|
||||
}
|
||||
stmt.executeBatch();
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.delete(sqls);
|
||||
}
|
||||
//------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -567,12 +562,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(final CompletionHandler<Void, FilterNode> handler, final Class<T> clazz, final FilterNode node) {
|
||||
delete(clazz, node);
|
||||
if (handler != null) handler.completed(null, node);
|
||||
}
|
||||
|
||||
private <T> void delete(final Connection conn, final EntityInfo<T> info, final FilterNode node) {
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
@@ -584,7 +573,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.delete(sql);
|
||||
}
|
||||
//------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -629,22 +617,15 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void update(final CompletionHandler<Void, T[]> handler, final T... values) {
|
||||
update(values);
|
||||
if (handler != null) handler.completed(null, values);
|
||||
}
|
||||
|
||||
private <T> void update(final Connection conn, final EntityInfo<T> info, T... values) {
|
||||
try {
|
||||
Class clazz = info.getType();
|
||||
if (!info.isVirtualEntity()) {
|
||||
if (debug.get()) logger.finest(clazz.getSimpleName() + " update sql=" + info.updateSQL);
|
||||
final String updateSQL = info.getUpdateSQL(values[0]);
|
||||
if (debug.get()) logger.finest(clazz.getSimpleName() + " update sql=" + updateSQL);
|
||||
final Attribute<T, Serializable> primary = info.getPrimary();
|
||||
final PreparedStatement prestmt = conn.prepareStatement(info.updateSQL);
|
||||
final PreparedStatement prestmt = conn.prepareStatement(updateSQL);
|
||||
Attribute<T, Serializable>[] attrs = info.updateAttributes;
|
||||
String[] sqls = null;
|
||||
if (writeListener == null) {
|
||||
for (final T value : values) {
|
||||
int i = 0;
|
||||
for (Attribute<T, Serializable> attr : attrs) {
|
||||
@@ -653,36 +634,8 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
prestmt.setObject(++i, primary.get(value));
|
||||
prestmt.addBatch();
|
||||
}
|
||||
} else {
|
||||
char[] sqlchars = info.updateSQL.toCharArray();
|
||||
sqls = new String[values.length];
|
||||
CharSequence[] ps = new CharSequence[attrs.length];
|
||||
int index = 0;
|
||||
for (final T value : values) {
|
||||
int i = 0;
|
||||
for (Attribute<T, Serializable> attr : attrs) {
|
||||
Object a = attr.get(value);
|
||||
ps[i] = FilterNode.formatToString(a);
|
||||
prestmt.setObject(++i, a);
|
||||
}
|
||||
prestmt.setObject(++i, primary.get(value));
|
||||
prestmt.addBatch();
|
||||
//-----------------------------
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
i = 0;
|
||||
for (char ch : sqlchars) {
|
||||
if (ch == '?') {
|
||||
sb.append(ps[i++]);
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
}
|
||||
sqls[index++] = sb.toString();
|
||||
}
|
||||
}
|
||||
prestmt.executeBatch();
|
||||
prestmt.close();
|
||||
if (writeListener != null) writeListener.update(sqls);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -720,22 +673,15 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, final Serializable value) {
|
||||
updateColumn(clazz, id, column, value);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
private <T> void updateColumn(Connection conn, final EntityInfo<T> info, Serializable id, String column, Serializable value) {
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
String sql = "UPDATE " + info.getTable(id) + " SET " + info.getSQLColumn(null, column) + " = "
|
||||
+ FilterNode.formatToString(value) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
|
||||
+ info.formatToString(value) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
|
||||
if (debug.get()) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.update(sql);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -773,12 +719,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final CompletionHandler<Void, FilterNode> handler, final Class<T> clazz, final String column, final Serializable value, FilterNode node) {
|
||||
updateColumn(clazz, column, value, node);
|
||||
if (handler != null) handler.completed(null, node);
|
||||
}
|
||||
|
||||
private <T> void updateColumn(Connection conn, final EntityInfo<T> info, String column, Serializable value, FilterNode node) {
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
@@ -787,12 +727,11 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
CharSequence where = node.createSQLExpress(info, joinTabalis);
|
||||
|
||||
String sql = "UPDATE " + info.getTable(node) + " a SET " + info.getSQLColumn("a", column) + " = "
|
||||
+ FilterNode.formatToString(value) + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
|
||||
+ info.formatToString(value) + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
|
||||
if (debug.get()) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.update(sql);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -831,12 +770,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnIncrement(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, long incvalue) {
|
||||
updateColumnIncrement(clazz, id, column, incvalue);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
private <T> void updateColumnIncrement(Connection conn, final EntityInfo<T> info, Serializable id, String column, long incvalue) {
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
@@ -847,7 +780,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.update(sql);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -887,12 +819,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnAnd(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, long incvalue) {
|
||||
updateColumnAnd(clazz, id, column, incvalue);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
private <T> void updateColumnAnd(Connection conn, final EntityInfo<T> info, Serializable id, String column, long andvalue) {
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
@@ -903,7 +829,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.update(sql);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -943,12 +868,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnOr(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, long incvalue) {
|
||||
updateColumnOr(clazz, id, column, incvalue);
|
||||
if (handler != null) handler.completed(null, id);
|
||||
}
|
||||
|
||||
private <T> void updateColumnOr(Connection conn, final EntityInfo<T> info, Serializable id, String column, long orvalue) {
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
@@ -959,7 +878,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.update(sql);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -996,12 +914,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumns(final CompletionHandler<Void, T> handler, final T bean, final String... columns) {
|
||||
updateColumns(bean, columns);
|
||||
if (handler != null) handler.completed(null, bean);
|
||||
}
|
||||
|
||||
private <T> void updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final String... columns) {
|
||||
if (bean == null || columns.length < 1) return;
|
||||
try {
|
||||
@@ -1016,7 +928,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
attrs.add(attr);
|
||||
if (!virtual) {
|
||||
if (setsql.length() > 0) setsql.append(", ");
|
||||
setsql.append(info.getSQLColumn(null, col)).append(" = ").append(FilterNode.formatToString(attr.get(bean)));
|
||||
setsql.append(info.getSQLColumn(null, col)).append(" = ").append(info.formatToString(attr.get(bean)));
|
||||
}
|
||||
}
|
||||
if (!virtual) {
|
||||
@@ -1025,7 +937,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.update(sql);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -1060,12 +971,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumns(final CompletionHandler<Void, FilterNode> handler, final T bean, final FilterNode node, final String... columns) {
|
||||
updateColumns(bean, node, columns);
|
||||
if (handler != null) handler.completed(null, node);
|
||||
}
|
||||
|
||||
private <T> void updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final FilterNode node, final String... columns) {
|
||||
if (bean == null || node == null || columns.length < 1) return;
|
||||
try {
|
||||
@@ -1080,7 +985,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
attrs.add(attr);
|
||||
if (!virtual) {
|
||||
if (setsql.length() > 0) setsql.append(", ");
|
||||
setsql.append(info.getSQLColumn("a", col)).append(" = ").append(FilterNode.formatToString(attr.get(bean)));
|
||||
setsql.append(info.getSQLColumn("a", col)).append(" = ").append(info.formatToString(attr.get(bean)));
|
||||
}
|
||||
}
|
||||
if (!virtual) {
|
||||
@@ -1094,7 +999,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
if (writeListener != null) writeListener.update(sql);
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
@@ -1131,34 +1035,38 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
//-----------------------getNumberResult-----------------------------
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column) {
|
||||
return getNumberResult(entityClass, func, column, (FilterNode) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNumberResult(final CompletionHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final String column) {
|
||||
Number rs = getNumberResult(entityClass, func, column);
|
||||
if (handler != null) handler.completed(rs, column);
|
||||
return getNumberResult(entityClass, func, null, column, (FilterNode) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, FilterBean bean) {
|
||||
return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNumberResult(final CompletionHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) {
|
||||
getNumberResult(handler, entityClass, func, column, FilterNodeBean.createFilterNode(bean));
|
||||
return getNumberResult(entityClass, func, null, column, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterNode node) {
|
||||
return getNumberResult(entityClass, func, null, column, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column) {
|
||||
return getNumberResult(entityClass, func, defVal, column, (FilterNode) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, FilterBean bean) {
|
||||
return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) {
|
||||
final Connection conn = createReadSQLConnection();
|
||||
try {
|
||||
final EntityInfo info = loadEntityInfo(entityClass);
|
||||
final EntityCache cache = info.getCache();
|
||||
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
|
||||
if (node == null || node.isCacheUseable(this)) {
|
||||
return cache.getNumberResult(func, column, node);
|
||||
return cache.getNumberResult(func, defVal, column, node);
|
||||
}
|
||||
}
|
||||
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
|
||||
@@ -1168,7 +1076,7 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
|
||||
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql);
|
||||
final PreparedStatement prestmt = conn.prepareStatement(sql);
|
||||
Number rs = null;
|
||||
Number rs = defVal;
|
||||
ResultSet set = prestmt.executeQuery();
|
||||
if (set.next()) {
|
||||
rs = (Number) set.getObject(1);
|
||||
@@ -1183,34 +1091,17 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNumberResult(final CompletionHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, final FilterNode node) {
|
||||
Number rs = getNumberResult(entityClass, func, column, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
//-----------------------queryColumnMap-----------------------------
|
||||
@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) {
|
||||
return queryColumnMap(entityClass, keyColumn, func, funcColumn, (FilterNode) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, String> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) {
|
||||
Map<K, N> map = queryColumnMap(entityClass, keyColumn, func, funcColumn);
|
||||
if (handler != null) handler.completed(map, funcColumn);
|
||||
}
|
||||
|
||||
@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, FilterBean bean) {
|
||||
return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, FilterNode> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) {
|
||||
queryColumnMap(handler, entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) {
|
||||
final Connection conn = createReadSQLConnection();
|
||||
@@ -1247,12 +1138,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, FilterNode> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node) {
|
||||
Map<K, N> map = queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
|
||||
if (handler != null) handler.completed(map, node);
|
||||
}
|
||||
|
||||
//-----------------------find----------------------------
|
||||
/**
|
||||
* 根据主键获取对象
|
||||
@@ -1268,12 +1153,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return find(clazz, (SelectColumn) null, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final Serializable pk) {
|
||||
T rs = find(clazz, pk);
|
||||
if (handler != null) handler.completed(rs, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(Class<T> clazz, final SelectColumn selects, Serializable pk) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
@@ -1301,58 +1180,26 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final SelectColumn selects, final Serializable pk) {
|
||||
T rs = find(clazz, selects, pk);
|
||||
if (handler != null) handler.completed(rs, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final String column, final Serializable key) {
|
||||
return find(clazz, null, FilterNode.create(column, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final String column, final Serializable key) {
|
||||
T rs = find(clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final FilterBean bean) {
|
||||
return find(clazz, null, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
T rs = find(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final FilterNode node) {
|
||||
return find(clazz, null, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final FilterNode node) {
|
||||
T rs = find(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
|
||||
return find(clazz, selects, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
T rs = find(clazz, selects, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
@@ -1380,12 +1227,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
|
||||
T rs = find(clazz, selects, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean exists(Class<T> clazz, Serializable pk) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
@@ -1412,24 +1253,11 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void exists(final CompletionHandler<Boolean, Serializable> handler, final Class<T> clazz, final Serializable pk) {
|
||||
boolean rs = exists(clazz, pk);
|
||||
if (handler != null) handler.completed(rs, pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean exists(final Class<T> clazz, final FilterBean bean) {
|
||||
return exists(clazz, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void exists(final CompletionHandler<Boolean, FilterNode> handler, final Class<T> clazz, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
boolean rs = exists(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean exists(final Class<T> clazz, final FilterNode node) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
@@ -1456,81 +1284,37 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void exists(final CompletionHandler<Boolean, FilterNode> handler, final Class<T> clazz, final FilterNode node) {
|
||||
boolean rs = exists(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
//-----------------------list set----------------------------
|
||||
@Override
|
||||
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, String column, Serializable key) {
|
||||
return queryColumnSet(selectedColumn, clazz, FilterNode.create(column, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, final Serializable key) {
|
||||
HashSet<V> rs = queryColumnSet(selectedColumn, clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final FilterBean bean) {
|
||||
return new LinkedHashSet<>(queryColumnList(selectedColumn, clazz, bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
HashSet<V> rs = queryColumnSet(selectedColumn, clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterNode node) {
|
||||
return new LinkedHashSet<>(queryColumnList(selectedColumn, clazz, node));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterNode node) {
|
||||
HashSet<V> rs = queryColumnSet(selectedColumn, clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key) {
|
||||
return queryColumnList(selectedColumn, clazz, FilterNode.create(column, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, final Serializable key) {
|
||||
List<V> rs = queryColumnList(selectedColumn, clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterBean bean) {
|
||||
return (List<V>) queryColumnSheet(selectedColumn, clazz, null, bean).list(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterBean bean) {
|
||||
final FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
List<V> rs = queryColumnList(selectedColumn, clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterNode node) {
|
||||
return (List<V>) queryColumnSheet(selectedColumn, clazz, null, node).list(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterNode node) {
|
||||
List<V> rs = queryColumnList(selectedColumn, clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定参数查询对象某个字段的集合
|
||||
* <p>
|
||||
@@ -1548,13 +1332,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSheet(final CompletionHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
final FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
Sheet<V> rs = queryColumnSheet(selectedColumn, clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
Sheet<T> sheet = querySheet(true, true, clazz, SelectColumn.createIncludes(selectedColumn), flipper, node);
|
||||
@@ -1571,12 +1348,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return rs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V extends Serializable> void queryColumnSheet(final CompletionHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
Sheet<V> rs = queryColumnSheet(selectedColumn, clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
private <K extends Serializable, T> Map<K, T> formatMap(final Class<T> clazz, final Collection<T> list) {
|
||||
Map<K, T> map = new LinkedHashMap<>();
|
||||
if (list == null || list.isEmpty()) return map;
|
||||
@@ -1602,12 +1373,6 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return queryList(clazz, FilterNode.create(column, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, Serializable> handler, final Class<T> clazz, final String column, final Serializable key) {
|
||||
List<T> rs = queryList(clazz, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据过滤对象FilterBean查询对象集合
|
||||
*
|
||||
@@ -1622,24 +1387,11 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return queryList(clazz, (SelectColumn) null, bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
List<T> rs = queryList(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final FilterNode node) {
|
||||
return queryList(clazz, (SelectColumn) null, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final FilterNode node) {
|
||||
List<T> rs = queryList(clazz, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据过滤对象FilterBean查询对象集合, 对象只填充或排除SelectField指定的字段
|
||||
*
|
||||
@@ -1655,81 +1407,36 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return queryList(clazz, selects, (Flipper) null, bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
List<T> rs = queryList(clazz, selects, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
|
||||
return queryList(clazz, selects, (Flipper) null, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
|
||||
List<T> rs = queryList(clazz, selects, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key) {
|
||||
return queryList(clazz, flipper, FilterNode.create(column, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, Serializable> handler, final Class<T> clazz, final Flipper flipper, final String column, final Serializable key) {
|
||||
List<T> rs = queryList(clazz, flipper, column, key);
|
||||
if (handler != null) handler.completed(rs, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
return queryList(clazz, null, flipper, bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
List<T> rs = queryList(clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
return queryList(clazz, null, flipper, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
List<T> rs = queryList(clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
|
||||
return querySheet(true, false, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)).list(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
List<T> rs = queryList(clazz, selects, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
|
||||
return querySheet(true, false, clazz, selects, flipper, node).list(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
|
||||
List<T> rs = queryList(clazz, selects, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
//-----------------------sheet----------------------------
|
||||
/**
|
||||
* 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据
|
||||
@@ -1746,24 +1453,11 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return querySheet(clazz, null, flipper, bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
Sheet<T> rs = querySheet(clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
return querySheet(clazz, null, flipper, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
|
||||
Sheet<T> rs = querySheet(clazz, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据, 对象只填充或排除SelectField指定的字段
|
||||
*
|
||||
@@ -1780,24 +1474,11 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
return querySheet(true, true, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
|
||||
FilterNode node = FilterNodeBean.createFilterNode(bean);
|
||||
Sheet<T> rs = querySheet(clazz, selects, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
|
||||
return querySheet(true, true, clazz, selects, flipper, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
|
||||
Sheet<T> rs = querySheet(clazz, selects, flipper, node);
|
||||
if (handler != null) handler.completed(rs, node);
|
||||
}
|
||||
|
||||
private <T> Sheet<T> querySheet(final boolean readcache, final boolean needtotal, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
|
||||
@@ -1,21 +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.source;
|
||||
|
||||
/**
|
||||
* @Resource(name = "property.datasource.nodeid")
|
||||
*
|
||||
* <p> 详情见: http://redkale.org
|
||||
* @author zhangjx
|
||||
*/
|
||||
public interface DataSQLListener {
|
||||
|
||||
public void insert(String... sqls);
|
||||
|
||||
public void update(String... sqls);
|
||||
|
||||
public void delete(String... sqls);
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.redkale.source;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
@@ -33,9 +32,6 @@ public interface DataSource {
|
||||
*/
|
||||
public <T> void insert(final T... values);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T> void insert(final CompletionHandler<Void, T[]> handler, final T... values);
|
||||
|
||||
//-------------------------delete--------------------------
|
||||
/**
|
||||
* 删除对象, 必须是Entity对象
|
||||
@@ -57,13 +53,6 @@ public interface DataSource {
|
||||
|
||||
public <T> void delete(final Class<T> clazz, final FilterNode node);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T> void delete(final CompletionHandler<Void, T[]> handler, final T... values);
|
||||
|
||||
public <T> void delete(final CompletionHandler<Void, Serializable[]> handler, final Class<T> clazz, final Serializable... ids);
|
||||
|
||||
public <T> void delete(final CompletionHandler<Void, FilterNode> handler, final Class<T> clazz, final FilterNode node);
|
||||
|
||||
//------------------------update---------------------------
|
||||
/**
|
||||
* 更新对象, 必须是Entity对象
|
||||
@@ -87,23 +76,6 @@ public interface DataSource {
|
||||
|
||||
public <T> void updateColumns(final T bean, final FilterNode node, final String... columns);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T> void update(final CompletionHandler<Void, T[]> handler, final T... values);
|
||||
|
||||
public <T> void updateColumn(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, final Serializable value);
|
||||
|
||||
public <T> void updateColumn(final CompletionHandler<Void, FilterNode> handler, final Class<T> clazz, final String column, final Serializable value, final FilterNode node);
|
||||
|
||||
public <T> void updateColumnIncrement(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, long incvalue);
|
||||
|
||||
public <T> void updateColumnAnd(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, long incvalue);
|
||||
|
||||
public <T> void updateColumnOr(final CompletionHandler<Void, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, long incvalue);
|
||||
|
||||
public <T> void updateColumns(final CompletionHandler<Void, T> handler, final T bean, final String... columns);
|
||||
|
||||
public <T> void updateColumns(final CompletionHandler<Void, FilterNode> handler, final T bean, final FilterNode node, final String... columns);
|
||||
|
||||
//############################################# 查询接口 #############################################
|
||||
//-----------------------getXXXXResult-----------------------------
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column);
|
||||
@@ -112,25 +84,18 @@ public interface DataSource {
|
||||
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterNode node);
|
||||
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column);
|
||||
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterBean bean);
|
||||
|
||||
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node);
|
||||
|
||||
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn);
|
||||
|
||||
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean);
|
||||
|
||||
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public void getNumberResult(final CompletionHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final String column);
|
||||
|
||||
public void getNumberResult(final CompletionHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, final FilterBean bean);
|
||||
|
||||
public void getNumberResult(final CompletionHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, final FilterNode node);
|
||||
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, String> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn);
|
||||
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, FilterNode> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean);
|
||||
|
||||
public <T, K extends Serializable, N extends Number> void queryColumnMap(final CompletionHandler<Map<K, N>, FilterNode> handler, final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node);
|
||||
|
||||
//-----------------------find----------------------------
|
||||
/**
|
||||
* 根据主键获取对象
|
||||
@@ -161,27 +126,6 @@ public interface DataSource {
|
||||
|
||||
public <T> boolean exists(final Class<T> clazz, final FilterNode node);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final Serializable pk);
|
||||
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final SelectColumn selects, final Serializable pk);
|
||||
|
||||
public <T> void find(final CompletionHandler<T, Serializable> handler, final Class<T> clazz, final String column, final Serializable key);
|
||||
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final FilterBean bean);
|
||||
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final FilterNode node);
|
||||
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterBean bean);
|
||||
|
||||
public <T> void find(final CompletionHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterNode node);
|
||||
|
||||
public <T> void exists(final CompletionHandler<Boolean, Serializable> handler, final Class<T> clazz, final Serializable pk);
|
||||
|
||||
public <T> void exists(final CompletionHandler<Boolean, FilterNode> handler, final Class<T> clazz, final FilterBean bean);
|
||||
|
||||
public <T> void exists(final CompletionHandler<Boolean, FilterNode> handler, final Class<T> clazz, final FilterNode node);
|
||||
|
||||
//-----------------------list set----------------------------
|
||||
/**
|
||||
* 根据指定字段值查询对象某个字段的集合
|
||||
@@ -207,19 +151,6 @@ public interface DataSource {
|
||||
|
||||
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterNode node);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
|
||||
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterBean bean);
|
||||
|
||||
public <T, V extends Serializable> void queryColumnSet(final CompletionHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterNode node);
|
||||
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, final Serializable key);
|
||||
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterBean bean);
|
||||
|
||||
public <T, V extends Serializable> void queryColumnList(final CompletionHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final FilterNode node);
|
||||
|
||||
/**
|
||||
* 根据指定参数查询对象某个字段的集合
|
||||
*
|
||||
@@ -236,11 +167,6 @@ public interface DataSource {
|
||||
|
||||
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T, V extends Serializable> void queryColumnSheet(final CompletionHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean);
|
||||
|
||||
public <T, V extends Serializable> void queryColumnSheet(final CompletionHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node);
|
||||
|
||||
/**
|
||||
* 根据指定字段值查询对象集合
|
||||
*
|
||||
@@ -271,27 +197,6 @@ public interface DataSource {
|
||||
|
||||
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T> void queryList(final CompletionHandler<List<T>, Serializable> handler, final Class<T> clazz, final String column, final Serializable key);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final FilterBean bean);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final FilterNode node);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterBean bean);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final FilterNode node);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, Serializable> handler, final Class<T> clazz, final Flipper flipper, final String column, final Serializable key);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterBean bean);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterNode node);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean);
|
||||
|
||||
public <T> void queryList(final CompletionHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node);
|
||||
|
||||
//-----------------------sheet----------------------------
|
||||
/**
|
||||
* 根据指定参数查询对象某个对象的集合页
|
||||
@@ -311,15 +216,6 @@ public interface DataSource {
|
||||
|
||||
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node);
|
||||
|
||||
//----------------------异步版---------------------------------
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterBean bean);
|
||||
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, final FilterNode node);
|
||||
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean);
|
||||
|
||||
public <T> void querySheet(final CompletionHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node);
|
||||
|
||||
//-----------------------direct----------------------------
|
||||
/**
|
||||
* 直接本地执行SQL语句进行查询,远程模式不可用
|
||||
|
||||
@@ -10,20 +10,6 @@ import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
*
|
||||
* <pre>
|
||||
* int 10万-100万 (36进制 4位) 255t - lflr 长度4 rewrite "^/dir/(\w+)/((\w{2})(\w{2})\..*)$" /$1/$3/$2 last;
|
||||
* int 1000万-6000万 (36进制 5位) 5yc1t - zq0an 长度5-6 rewrite "^/dir/(\w+)/((\w{2})(\w{2})(\w\w?)\..*)$" /$1/$3/$4/$2 last;
|
||||
* int 2亿-20亿 (36进制 6位) 3b2ozl - x2qxvk
|
||||
* long 30亿-770亿 (36进制 7位) 1dm4etd - zdft88v 长度7-8 rewrite "^/dir/(\w+)/((\w{2})(\w{2})(\w{2})(\w\w?)\..*)$" /$1/$3/$4/$5/$2 last;
|
||||
* long 1000亿-2万亿 (36进制 8位) 19xtf1tt - piscd0jj
|
||||
* 随机文件名: (32进制 26位) 26-27长度
|
||||
* #文件名 长度: 26 (1)
|
||||
* rewrite "^/dir/(\w+)/((\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{14})\..*)$" /dir/$1/$3/$4/$5/$6/$7/$8/$2;
|
||||
* #文件名 长度: 26 (2)
|
||||
* rewrite "^/dir/(\w+)/(\w\w/\w\w/\w\w/\w\w/\w\w/\w\w)/(\w{12}(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})(\w{2})\..*)$" /$1/$2/$4/$5/$6/$7/$8/$9/$3 last;
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
|
||||
24
src/org/redkale/source/DistributeTable.java
Normal file
24
src/org/redkale/source/DistributeTable.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Target({TYPE})
|
||||
@Retention(RUNTIME)
|
||||
public @interface DistributeTable {
|
||||
|
||||
Class<? extends DistributeTableStrategy> strategy();
|
||||
}
|
||||
29
src/org/redkale/source/DistributeTableStrategy.java
Normal file
29
src/org/redkale/source/DistributeTableStrategy.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <T> Entity类型
|
||||
*/
|
||||
public interface DistributeTableStrategy<T> {
|
||||
|
||||
default String getTable(String table, Serializable primary) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getTable(String table, FilterNode node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getTable(String table, T bean);
|
||||
}
|
||||
@@ -71,8 +71,7 @@ public final class EntityCache<T> {
|
||||
java.lang.reflect.Field field = type.getDeclaredField(m);
|
||||
if (field.getAnnotation(Transient.class) != null) return false;
|
||||
Column column = field.getAnnotation(Column.class);
|
||||
if (column != null && !column.updatable()) return false;
|
||||
return true;
|
||||
return (column == null || column.updatable());
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
@@ -109,14 +108,14 @@ public final class EntityCache<T> {
|
||||
public T find(Serializable id) {
|
||||
if (id == null) return null;
|
||||
T rs = map.get(id);
|
||||
return rs == null ? null : (needcopy ? newReproduce.copy(this.creator.create(), rs) : rs);
|
||||
return rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs);
|
||||
}
|
||||
|
||||
public T find(final SelectColumn selects, final Serializable id) {
|
||||
if (id == null) return null;
|
||||
T rs = map.get(id);
|
||||
if (rs == null) return null;
|
||||
if (selects == null) return (needcopy ? newReproduce.copy(this.creator.create(), rs) : rs);
|
||||
if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs);
|
||||
T t = this.creator.create();
|
||||
for (Attribute attr : this.info.attributes) {
|
||||
if (selects.test(attr.field())) attr.set(t, attr.get(rs));
|
||||
@@ -130,7 +129,7 @@ public final class EntityCache<T> {
|
||||
if (filter != null) stream = stream.filter(filter);
|
||||
Optional<T> opt = stream.findFirst();
|
||||
if (!opt.isPresent()) return null;
|
||||
if (selects == null) return (needcopy ? newReproduce.copy(this.creator.create(), opt.get()) : opt.get());
|
||||
if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), opt.get()) : opt.get());
|
||||
T rs = opt.get();
|
||||
T t = this.creator.create();
|
||||
for (Attribute attr : this.info.attributes) {
|
||||
@@ -221,7 +220,7 @@ public final class EntityCache<T> {
|
||||
return rs;
|
||||
}
|
||||
|
||||
public <V> Number getNumberResult(final FilterFunc func, final String column, FilterNode node) {
|
||||
public <V> Number getNumberResult(final FilterFunc func, final Number defResult, final String column, final FilterNode node) {
|
||||
final Attribute<T, Serializable> attr = column == null ? null : info.getAttribute(column);
|
||||
final Predicate<T> filter = node == null ? null : node.createPredicate(this);
|
||||
Stream<T> stream = this.list.stream();
|
||||
@@ -229,15 +228,20 @@ public final class EntityCache<T> {
|
||||
switch (func) {
|
||||
case AVG:
|
||||
if (attr.type() == int.class || attr.type() == Integer.class) {
|
||||
return (int) stream.mapToInt(x -> (Integer) attr.get(x)).average().orElse(0);
|
||||
OptionalDouble rs = stream.mapToInt(x -> (Integer) attr.get(x)).average();
|
||||
return rs.isPresent() ? (int) rs.getAsDouble() : defResult;
|
||||
} else if (attr.type() == long.class || attr.type() == Long.class) {
|
||||
return (long) stream.mapToLong(x -> (Long) attr.get(x)).average().orElse(0);
|
||||
OptionalDouble rs = stream.mapToLong(x -> (Long) attr.get(x)).average();
|
||||
return rs.isPresent() ? (long) rs.getAsDouble() : defResult;
|
||||
} else if (attr.type() == short.class || attr.type() == Short.class) {
|
||||
return (short) stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).average().orElse(0);
|
||||
OptionalDouble rs = stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).average();
|
||||
return rs.isPresent() ? (short) rs.getAsDouble() : defResult;
|
||||
} else if (attr.type() == float.class || attr.type() == Float.class) {
|
||||
return (float) stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).average().orElse(0);
|
||||
OptionalDouble rs = stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).average();
|
||||
return rs.isPresent() ? (float) rs.getAsDouble() : defResult;
|
||||
} else if (attr.type() == double.class || attr.type() == Double.class) {
|
||||
return stream.mapToDouble(x -> (Double) attr.get(x)).average().orElse(0);
|
||||
OptionalDouble rs = stream.mapToDouble(x -> (Double) attr.get(x)).average();
|
||||
return rs.isPresent() ? rs.getAsDouble() : defResult;
|
||||
}
|
||||
throw new RuntimeException("getNumberResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
case COUNT:
|
||||
@@ -247,29 +251,39 @@ public final class EntityCache<T> {
|
||||
|
||||
case MAX:
|
||||
if (attr.type() == int.class || attr.type() == Integer.class) {
|
||||
return stream.mapToInt(x -> (Integer) attr.get(x)).max().orElse(0);
|
||||
OptionalInt rs = stream.mapToInt(x -> (Integer) attr.get(x)).max();
|
||||
return rs.isPresent() ? rs.getAsInt() : defResult;
|
||||
} else if (attr.type() == long.class || attr.type() == Long.class) {
|
||||
return stream.mapToLong(x -> (Long) attr.get(x)).max().orElse(0);
|
||||
OptionalLong rs = stream.mapToLong(x -> (Long) attr.get(x)).max();
|
||||
return rs.isPresent() ? rs.getAsLong() : defResult;
|
||||
} else if (attr.type() == short.class || attr.type() == Short.class) {
|
||||
return (short) stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).max().orElse(0);
|
||||
OptionalInt rs = stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).max();
|
||||
return rs.isPresent() ? (short) rs.getAsInt() : defResult;
|
||||
} else if (attr.type() == float.class || attr.type() == Float.class) {
|
||||
return (float) stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).max().orElse(0);
|
||||
OptionalDouble rs = stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).max();
|
||||
return rs.isPresent() ? (float) rs.getAsDouble() : defResult;
|
||||
} else if (attr.type() == double.class || attr.type() == Double.class) {
|
||||
return stream.mapToDouble(x -> (Double) attr.get(x)).max().orElse(0);
|
||||
OptionalDouble rs = stream.mapToDouble(x -> (Double) attr.get(x)).max();
|
||||
return rs.isPresent() ? rs.getAsDouble() : defResult;
|
||||
}
|
||||
throw new RuntimeException("getNumberResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
|
||||
case MIN:
|
||||
if (attr.type() == int.class || attr.type() == Integer.class) {
|
||||
return stream.mapToInt(x -> (Integer) attr.get(x)).min().orElse(0);
|
||||
OptionalInt rs = stream.mapToInt(x -> (Integer) attr.get(x)).min();
|
||||
return rs.isPresent() ? rs.getAsInt() : defResult;
|
||||
} else if (attr.type() == long.class || attr.type() == Long.class) {
|
||||
return stream.mapToLong(x -> (Long) attr.get(x)).min().orElse(0);
|
||||
OptionalLong rs = stream.mapToLong(x -> (Long) attr.get(x)).min();
|
||||
return rs.isPresent() ? rs.getAsLong() : defResult;
|
||||
} else if (attr.type() == short.class || attr.type() == Short.class) {
|
||||
return (short) stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).min().orElse(0);
|
||||
OptionalInt rs = stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).min();
|
||||
return rs.isPresent() ? (short) rs.getAsInt() : defResult;
|
||||
} else if (attr.type() == float.class || attr.type() == Float.class) {
|
||||
return (float) stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).min().orElse(0);
|
||||
OptionalDouble rs = stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).min();
|
||||
return rs.isPresent() ? (float) rs.getAsDouble() : defResult;
|
||||
} else if (attr.type() == double.class || attr.type() == Double.class) {
|
||||
return stream.mapToDouble(x -> (Double) attr.get(x)).min().orElse(0);
|
||||
OptionalDouble rs = stream.mapToDouble(x -> (Double) attr.get(x)).min();
|
||||
return rs.isPresent() ? rs.getAsDouble() : defResult;
|
||||
}
|
||||
throw new RuntimeException("getNumberResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
|
||||
@@ -287,7 +301,7 @@ public final class EntityCache<T> {
|
||||
}
|
||||
throw new RuntimeException("getNumberResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
}
|
||||
return -1;
|
||||
return defResult;
|
||||
}
|
||||
|
||||
public Sheet<T> querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node) {
|
||||
@@ -310,7 +324,7 @@ public final class EntityCache<T> {
|
||||
if (flipper != null) stream = stream.skip(flipper.getOffset()).limit(flipper.getLimit());
|
||||
final List<T> rs = new ArrayList<>();
|
||||
if (selects == null) {
|
||||
Consumer<? super T> action = x -> rs.add(needcopy ? newReproduce.copy(creator.create(), x) : x);
|
||||
Consumer<? super T> action = x -> rs.add(needcopy ? newReproduce.apply(creator.create(), x) : x);
|
||||
if (comparator != null) {
|
||||
stream.forEachOrdered(action);
|
||||
} else {
|
||||
@@ -340,7 +354,7 @@ public final class EntityCache<T> {
|
||||
|
||||
public void insert(T value) {
|
||||
if (value == null) return;
|
||||
final T rs = newReproduce.copy(this.creator.create(), value); //确保同一主键值的map与list中的对象必须共用。
|
||||
final T rs = newReproduce.apply(this.creator.create(), value); //确保同一主键值的map与list中的对象必须共用。
|
||||
T old = this.map.put(this.primary.get(rs), rs);
|
||||
if (old == null) {
|
||||
this.list.add(rs);
|
||||
@@ -373,7 +387,7 @@ public final class EntityCache<T> {
|
||||
if (value == null) return;
|
||||
T rs = this.map.get(this.primary.get(value));
|
||||
if (rs == null) return;
|
||||
this.chgReproduce.copy(rs, value);
|
||||
this.chgReproduce.apply(rs, value);
|
||||
}
|
||||
|
||||
public T update(final T value, Collection<Attribute<T, Serializable>> attrs) {
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class EntityInfo<T> {
|
||||
private final Class<T> type;
|
||||
|
||||
//类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null
|
||||
private final String table;
|
||||
final String table;
|
||||
|
||||
private final Creator<T> creator;
|
||||
|
||||
@@ -62,19 +62,27 @@ public final class EntityInfo<T> {
|
||||
|
||||
final String notcontainSQL; //用于反向LIKE使用
|
||||
|
||||
final String tablenotexistSqlstates; //用于判断表不存在的使用, 多个SQLState用;隔开
|
||||
|
||||
final String tablecopySQL; //用于复制表结构使用
|
||||
|
||||
final Set<String> tables = new HashSet<>(); //用于存在table_20160202类似这种分布式表
|
||||
|
||||
final DistributeTableStrategy<T> tableStrategy;
|
||||
|
||||
final String querySQL;
|
||||
|
||||
private final Attribute<T, Serializable>[] queryAttributes; //数据库中所有字段
|
||||
|
||||
final String insertSQL;
|
||||
private final String insertSQL;
|
||||
|
||||
final Attribute<T, Serializable>[] insertAttributes; //数据库中所有可新增字段
|
||||
|
||||
final String updateSQL;
|
||||
private final String updateSQL;
|
||||
|
||||
final Attribute<T, Serializable>[] updateAttributes; //数据库中所有可更新字段
|
||||
|
||||
final String deleteSQL;
|
||||
private final String deleteSQL;
|
||||
|
||||
private final int logLevel;
|
||||
|
||||
@@ -85,6 +93,8 @@ public final class EntityInfo<T> {
|
||||
|
||||
final boolean autoGenerated;
|
||||
|
||||
final boolean autouuid;
|
||||
|
||||
final boolean distributed;
|
||||
|
||||
boolean initedPrimaryValue = false;
|
||||
@@ -145,6 +155,15 @@ public final class EntityInfo<T> {
|
||||
this.fullloader = fullloader;
|
||||
this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? t.name() : (t.catalog() + '.' + t.name());
|
||||
}
|
||||
DistributeTable dt = type.getAnnotation(DistributeTable.class);
|
||||
DistributeTableStrategy dts = null;
|
||||
try {
|
||||
dts = (dt == null) ? null : dt.strategy().newInstance();
|
||||
} catch (Exception e) {
|
||||
logger.severe(type + " init DistributeTableStrategy error", e);
|
||||
}
|
||||
this.tableStrategy = dts;
|
||||
|
||||
this.creator = Creator.create(type);
|
||||
Attribute idAttr0 = null;
|
||||
Map<String, String> aliasmap0 = null;
|
||||
@@ -156,6 +175,7 @@ public final class EntityInfo<T> {
|
||||
List<String> updatecols = new ArrayList<>();
|
||||
List<Attribute<T, Serializable>> updateattrs = new ArrayList<>();
|
||||
boolean auto = false;
|
||||
boolean uuid = false;
|
||||
boolean sqldistribute = false;
|
||||
int allocationSize0 = 0;
|
||||
|
||||
@@ -196,6 +216,10 @@ public final class EntityInfo<T> {
|
||||
allocationSize0 = dg.allocationSize();
|
||||
primaryValue.set(dg.initialValue());
|
||||
}
|
||||
if (gv != null && field.getType() == String.class) { //UUID
|
||||
uuid = true;
|
||||
auto = false;
|
||||
}
|
||||
if (!auto) {
|
||||
insertcols.add(sqlfield);
|
||||
insertattrs.add(attr);
|
||||
@@ -231,14 +255,14 @@ public final class EntityInfo<T> {
|
||||
if (insertsb2.length() > 0) insertsb2.append(',');
|
||||
insertsb2.append('?');
|
||||
}
|
||||
this.insertSQL = "INSERT INTO " + table + "(" + insertsb + ") VALUES(" + insertsb2 + ")";
|
||||
this.insertSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsb2 + ")";
|
||||
StringBuilder updatesb = new StringBuilder();
|
||||
for (String col : updatecols) {
|
||||
if (updatesb.length() > 0) updatesb.append(", ");
|
||||
updatesb.append(col).append(" = ?");
|
||||
}
|
||||
this.updateSQL = "UPDATE " + table + " SET " + updatesb + " WHERE " + getPrimarySQLColumn(null) + " = ?";
|
||||
this.deleteSQL = "DELETE FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = ?";
|
||||
this.updateSQL = "UPDATE " + (this.tableStrategy == null ? table : "${newtable}") + " SET " + updatesb + " WHERE " + getPrimarySQLColumn(null) + " = ?";
|
||||
this.deleteSQL = "DELETE FROM " + (this.tableStrategy == null ? table : "${newtable}") + " WHERE " + getPrimarySQLColumn(null) + " = ?";
|
||||
this.querySQL = "SELECT * FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = ?";
|
||||
} else {
|
||||
this.insertSQL = null;
|
||||
@@ -247,6 +271,7 @@ public final class EntityInfo<T> {
|
||||
this.querySQL = null;
|
||||
}
|
||||
this.autoGenerated = auto;
|
||||
this.autouuid = uuid;
|
||||
this.distributed = sqldistribute;
|
||||
this.allocationSize = allocationSize0;
|
||||
//----------------cache--------------
|
||||
@@ -259,9 +284,16 @@ public final class EntityInfo<T> {
|
||||
if (conf == null) conf = new Properties();
|
||||
this.containSQL = conf.getProperty(JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0");
|
||||
this.notcontainSQL = conf.getProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0");
|
||||
|
||||
this.tablenotexistSqlstates = ";" + conf.getProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";";
|
||||
this.tablecopySQL = conf.getProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}");
|
||||
}
|
||||
|
||||
public void createPrimaryValue(T src) {
|
||||
if (autouuid) {
|
||||
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());
|
||||
@@ -295,16 +327,37 @@ public final class EntityInfo<T> {
|
||||
return table == null;
|
||||
}
|
||||
|
||||
public String getInsertSQL(T bean) {
|
||||
if (this.tableStrategy == null) return insertSQL;
|
||||
return insertSQL.replace("${newtable}", getTable(bean));
|
||||
}
|
||||
|
||||
public String getUpdateSQL(T bean) {
|
||||
if (this.tableStrategy == null) return updateSQL;
|
||||
return updateSQL.replace("${newtable}", getTable(bean));
|
||||
}
|
||||
|
||||
public String getDeleteSQL(T bean) {
|
||||
if (this.tableStrategy == null) return deleteSQL;
|
||||
return deleteSQL.replace("${newtable}", getTable(bean));
|
||||
}
|
||||
|
||||
public String getTable(Serializable primary) {
|
||||
return table;
|
||||
if (tableStrategy == null) return table;
|
||||
String t = tableStrategy.getTable(table, primary);
|
||||
return t == null || t.isEmpty() ? table : t;
|
||||
}
|
||||
|
||||
public String getTable(FilterNode node) {
|
||||
return table;
|
||||
if (tableStrategy == null) return table;
|
||||
String t = tableStrategy.getTable(table, node);
|
||||
return t == null || t.isEmpty() ? table : t;
|
||||
}
|
||||
|
||||
public String getTable(T bean) {
|
||||
return table;
|
||||
if (tableStrategy == null) return table;
|
||||
String t = tableStrategy.getTable(table, bean);
|
||||
return t == null || t.isEmpty() ? table : t;
|
||||
}
|
||||
|
||||
public Attribute<T, Serializable> getPrimary() {
|
||||
@@ -379,25 +432,53 @@ public final class EntityInfo<T> {
|
||||
return l.intValue() >= this.logLevel;
|
||||
}
|
||||
|
||||
protected String formatToString(Object value) {
|
||||
if (value == null) return null;
|
||||
if (value instanceof CharSequence) {
|
||||
return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\'').toString();
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
protected T getValue(final SelectColumn sels, final ResultSet set) throws SQLException {
|
||||
T obj = creator.create();
|
||||
for (Attribute<T, Serializable> attr : queryAttributes) {
|
||||
if (sels == null || sels.test(attr.field())) {
|
||||
Serializable o = (Serializable) set.getObject(this.getSQLColumn(null, attr.field()));
|
||||
final Class t = attr.type();
|
||||
if (t.isPrimitive()) {
|
||||
if (o != null) {
|
||||
Class t = attr.type();
|
||||
if (t == int.class) {
|
||||
o = ((Number) o).intValue();
|
||||
} else if (t == short.class) {
|
||||
o = ((Number) o).shortValue();
|
||||
} else if (t == long.class) {
|
||||
o = ((Number) o).longValue();
|
||||
} else if (t == short.class) {
|
||||
o = ((Number) o).shortValue();
|
||||
} else if (t == float.class) {
|
||||
o = ((Number) o).floatValue();
|
||||
} else if (t == double.class) {
|
||||
o = ((Number) o).doubleValue();
|
||||
} else if (t == byte.class) {
|
||||
o = ((Number) o).byteValue();
|
||||
} else if (t == char.class) {
|
||||
o = (char) ((Number) o).intValue();
|
||||
}
|
||||
} else if (t == int.class) {
|
||||
o = 0;
|
||||
} else if (t == long.class) {
|
||||
o = 0L;
|
||||
} else if (t == short.class) {
|
||||
o = (short) 0;
|
||||
} else if (t == float.class) {
|
||||
o = 0.0f;
|
||||
} else if (t == double.class) {
|
||||
o = 0.0d;
|
||||
} else if (t == byte.class) {
|
||||
o = (byte) 0;
|
||||
} else if (t == boolean.class) {
|
||||
o = false;
|
||||
} else if (t == char.class) {
|
||||
o = (char) 0;
|
||||
}
|
||||
}
|
||||
attr.set(obj, o);
|
||||
|
||||
@@ -34,6 +34,10 @@ public @interface FilterJoinColumn {
|
||||
* 多个关联字段, 默认使用join表(b)的主键, join表与被join表(a)的字段必须一样
|
||||
* 例如: SELECT a.* FROM user a INNER JOIN record b ON a.userid = b.userid AND a.usertype = b.usertype
|
||||
* 那么注解为: @FilterJoinColumn(table = Record.class, columns = {"userid", "usertype"})
|
||||
* <p>
|
||||
* columns中的字段名如果不一致,可以将两个字段名用=连接成一个字段名
|
||||
* 例如: SELECT a.* FROM user a INNER JOIN record b ON a.userid = b.buyerid AND a.usertype = b.usertype
|
||||
* 那么注解为: @FilterJoinColumn(table = Record.class, columns = {"userid=buyerid", "usertype"})
|
||||
*
|
||||
* @return 关联字段
|
||||
*/
|
||||
|
||||
@@ -128,14 +128,23 @@ public class FilterJoinNode extends FilterNode {
|
||||
if (filter == null && !more.get()) return rs;
|
||||
if (filter != null) {
|
||||
final Predicate<E> inner = filter;
|
||||
final String[][] localJoinColumns = new String[joinColumns.length][2];
|
||||
for (int i = 0; i < joinColumns.length; i++) {
|
||||
int pos = joinColumns[i].indexOf('=');
|
||||
if (pos > 0) {
|
||||
localJoinColumns[i] = new String[]{joinColumns[i].substring(0, pos), joinColumns[i].substring(pos + 1)};
|
||||
} else {
|
||||
localJoinColumns[i] = new String[]{joinColumns[i], joinColumns[i]};
|
||||
}
|
||||
}
|
||||
rs = new Predicate<T>() {
|
||||
|
||||
@Override
|
||||
public boolean test(final T t) {
|
||||
Predicate<E> joinPredicate = null;
|
||||
for (String joinColumn : joinColumns) {
|
||||
final Serializable key = cache.getAttribute(joinColumn).get(t);
|
||||
final Attribute<E, Serializable> joinAttr = joinCache.getAttribute(joinColumn);
|
||||
for (String[] localJoinColumn : localJoinColumns) {
|
||||
final Serializable key = cache.getAttribute(localJoinColumn[0]).get(t);
|
||||
final Attribute<E, Serializable> joinAttr = joinCache.getAttribute(localJoinColumn[1]);
|
||||
Predicate<E> p = (E e) -> key.equals(joinAttr.get(e));
|
||||
joinPredicate = joinPredicate == null ? p : joinPredicate.and(p);
|
||||
}
|
||||
@@ -145,9 +154,9 @@ public class FilterJoinNode extends FilterNode {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(" #-- ON ").append(joinColumns[0]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(joinColumns[0]);
|
||||
for (int i = 1; i < joinColumns.length; i++) {
|
||||
sb.append(" AND ").append(joinColumns[i]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(joinColumns[i]);
|
||||
sb.append(" #-- ON ").append(localJoinColumns[0][0]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(localJoinColumns[0][1]);
|
||||
for (int i = 1; i < localJoinColumns.length; i++) {
|
||||
sb.append(" AND ").append(localJoinColumns[i][0]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(localJoinColumns[i][1]);
|
||||
}
|
||||
sb.append(" --# ").append(inner.toString());
|
||||
return sb.toString();
|
||||
@@ -277,10 +286,12 @@ public class FilterJoinNode extends FilterNode {
|
||||
if (node.joinClass == null) return null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String[] joinColumns = node.joinColumns;
|
||||
int pos = joinColumns[0].indexOf('=');
|
||||
sb.append(" INNER JOIN ").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass))
|
||||
.append(" ON ").append(info.getSQLColumn("a", joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), joinColumns[0]));
|
||||
.append(" ON ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0]));
|
||||
for (int i = 1; i < joinColumns.length; i++) {
|
||||
sb.append(" AND ").append(info.getSQLColumn("a", joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), joinColumns[i]));
|
||||
pos = joinColumns[i].indexOf('=');
|
||||
sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i]));
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,12 @@ public class JDBCPoolSource {
|
||||
try {
|
||||
while (!this.isInterrupted()) {
|
||||
final WatchKey key = watcher.take();
|
||||
Thread.sleep(3000); //防止文件正在更新过程中去读取
|
||||
long d; //防止文件正在更新过程中去读取
|
||||
for (;;) {
|
||||
d = f.lastModified();
|
||||
Thread.sleep(2000L);
|
||||
if (d == f.lastModified()) break;
|
||||
}
|
||||
final Map<String, Properties> m = loadProperties(new FileInputStream(file));
|
||||
key.pollEvents().stream().forEach((event) -> {
|
||||
if (event.kind() != ENTRY_MODIFY) return;
|
||||
|
||||
@@ -23,16 +23,20 @@ public abstract class AnyValue {
|
||||
/**
|
||||
* 可读写的AnyValue默认实现类
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static final class DefaultAnyValue extends AnyValue {
|
||||
|
||||
/**
|
||||
* 区分name大小写的比较策略
|
||||
*
|
||||
*/
|
||||
public static final BiPredicate<String, String> EQUALS = (name1, name2) -> name1.equals(name2);
|
||||
|
||||
/**
|
||||
* 不区分name大小写的比较策略
|
||||
*/
|
||||
public static final BiPredicate<String, String> EQUALSIGNORE = (name1, name2) -> name1.equalsIgnoreCase(name2);
|
||||
|
||||
private final BiPredicate<String, String> predicate;
|
||||
@@ -41,34 +45,74 @@ public abstract class AnyValue {
|
||||
|
||||
private Entry<AnyValue>[] entityValues = new Entry[0];
|
||||
|
||||
/**
|
||||
* 创建空的DefaultAnyValue对象
|
||||
*
|
||||
* @return DefaultAnyValue对象
|
||||
*/
|
||||
public static final DefaultAnyValue create() {
|
||||
return new DefaultAnyValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建含name-value值的DefaultAnyValue对象
|
||||
*
|
||||
* @param name name
|
||||
* @param value value值
|
||||
*
|
||||
* @return DefaultAnyValue对象
|
||||
*/
|
||||
public static final DefaultAnyValue create(String name, String value) {
|
||||
DefaultAnyValue conf = new DefaultAnyValue();
|
||||
conf.addValue(name, value);
|
||||
return conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建含name-value值的DefaultAnyValue对象
|
||||
*
|
||||
* @param name name
|
||||
* @param value value值
|
||||
*
|
||||
* @return DefaultAnyValue对象
|
||||
*/
|
||||
public static final DefaultAnyValue create(String name, AnyValue value) {
|
||||
DefaultAnyValue conf = new DefaultAnyValue();
|
||||
conf.addValue(name, value);
|
||||
return conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个区分大小写比较策略的DefaultAnyValue对象
|
||||
*
|
||||
*/
|
||||
public DefaultAnyValue() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建DefaultAnyValue对象
|
||||
*
|
||||
* @param ignoreCase name是否不区分大小写
|
||||
*/
|
||||
public DefaultAnyValue(boolean ignoreCase) {
|
||||
this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建DefaultAnyValue对象
|
||||
*
|
||||
* @param predicate name比较策略
|
||||
*/
|
||||
public DefaultAnyValue(BiPredicate<String, String> predicate) {
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建共享此内容的DefaultAnyValue对象
|
||||
*
|
||||
* @return DefaultAnyValue对象
|
||||
*/
|
||||
public DefaultAnyValue duplicate() {
|
||||
DefaultAnyValue rs = new DefaultAnyValue(this.predicate);
|
||||
rs.stringValues = this.stringValues;
|
||||
@@ -211,6 +255,14 @@ public abstract class AnyValue {
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultAnyValue addValue(String name, boolean value) {
|
||||
return addValue(name, String.valueOf(value));
|
||||
}
|
||||
|
||||
public DefaultAnyValue addValue(String name, Number value) {
|
||||
return addValue(name, String.valueOf(value));
|
||||
}
|
||||
|
||||
public DefaultAnyValue addValue(String name, String value) {
|
||||
if (name == null) return this;
|
||||
int len = this.stringValues.length;
|
||||
@@ -321,7 +373,7 @@ public abstract class AnyValue {
|
||||
}
|
||||
}
|
||||
|
||||
public static AnyValue create() {
|
||||
public static DefaultAnyValue create() {
|
||||
return new DefaultAnyValue();
|
||||
}
|
||||
|
||||
@@ -378,6 +430,11 @@ public abstract class AnyValue {
|
||||
return value == null || value.length() == 0 ? defaultValue : Byte.decode(value);
|
||||
}
|
||||
|
||||
public byte getByteValue(int radix, String name, byte defaultValue) {
|
||||
String value = getValue(name);
|
||||
return value == null || value.length() == 0 ? defaultValue : (radix == 10 ? Byte.decode(value) : Byte.parseByte(value, radix));
|
||||
}
|
||||
|
||||
public char getCharValue(String name) {
|
||||
return getValue(name).charAt(0);
|
||||
}
|
||||
@@ -396,6 +453,11 @@ public abstract class AnyValue {
|
||||
return value == null || value.length() == 0 ? defaultValue : Short.decode(value);
|
||||
}
|
||||
|
||||
public short getShortValue(int radix, String name, short defaultValue) {
|
||||
String value = getValue(name);
|
||||
return value == null || value.length() == 0 ? defaultValue : (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix));
|
||||
}
|
||||
|
||||
public int getIntValue(String name) {
|
||||
return Integer.decode(getValue(name));
|
||||
}
|
||||
@@ -405,6 +467,11 @@ public abstract class AnyValue {
|
||||
return value == null || value.length() == 0 ? defaultValue : Integer.decode(value);
|
||||
}
|
||||
|
||||
public int getIntValue(int radix, String name, int defaultValue) {
|
||||
String value = getValue(name);
|
||||
return value == null || value.length() == 0 ? defaultValue : (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix));
|
||||
}
|
||||
|
||||
public long getLongValue(String name) {
|
||||
return Long.decode(getValue(name));
|
||||
}
|
||||
@@ -414,6 +481,11 @@ public abstract class AnyValue {
|
||||
return value == null || value.length() == 0 ? defaultValue : Long.decode(value);
|
||||
}
|
||||
|
||||
public long getLongValue(int radix, String name, long defaultValue) {
|
||||
String value = getValue(name);
|
||||
return value == null || value.length() == 0 ? defaultValue : (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix));
|
||||
}
|
||||
|
||||
public float getFloatValue(String name) {
|
||||
return Float.parseFloat(getValue(name));
|
||||
}
|
||||
|
||||
@@ -72,6 +72,12 @@ public class AsmMethodVisitor {
|
||||
return av;
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
if (debug) System.out.println("mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");");
|
||||
return av;
|
||||
}
|
||||
|
||||
public void visitParameter(String name, int access) {
|
||||
visitor.visitParameter(name, access);
|
||||
if (debug) System.out.println("mv.visitParameter(" + name + ", " + access + ");");
|
||||
@@ -82,6 +88,25 @@ public class AsmMethodVisitor {
|
||||
if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");");
|
||||
}
|
||||
|
||||
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
|
||||
visitor.visitFrame(type, nLocal, local, nStack, stack);
|
||||
if (debug) {
|
||||
String typestr = "" + type;
|
||||
if (type == -1) {
|
||||
typestr = "Opcodes.F_NEW";
|
||||
} else if (type == 1) {
|
||||
typestr = "Opcodes.F_APPEND";
|
||||
} else if (type == 2) {
|
||||
typestr = "Opcodes.F_CHOP";
|
||||
} else if (type == 3) {
|
||||
typestr = "Opcodes.F_SAME";
|
||||
} else if (type == 4) {
|
||||
typestr = "Opcodes.F_SAME1";
|
||||
}
|
||||
System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", " + nStack + ", " + Arrays.toString(stack) + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitJumpInsn(int opcode, Label var) { //调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建
|
||||
visitor.visitJumpInsn(opcode, var);
|
||||
if (debug) {
|
||||
|
||||
@@ -421,6 +421,8 @@ public interface Attribute<T, F> {
|
||||
column = tgetter.getReturnType();
|
||||
} else if (tsetter != null) {
|
||||
column = tsetter.getParameterTypes()[0];
|
||||
} else if (fieldtype == null) {
|
||||
throw new RuntimeException("[" + clazz + "]have no public field or setter or getter");
|
||||
}
|
||||
final Class pcolumn = column;
|
||||
if (column.isPrimitive()) column = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(column, 1), 0).getClass();
|
||||
|
||||
@@ -94,7 +94,7 @@ public final class ByteArray {
|
||||
/**
|
||||
* 将buf内容覆盖到本对象内容中
|
||||
*
|
||||
* @param buf
|
||||
* @param buf 目标容器
|
||||
*/
|
||||
public void copyTo(byte[] buf) {
|
||||
System.arraycopy(this.content, 0, buf, 0, count);
|
||||
@@ -103,7 +103,7 @@ public final class ByteArray {
|
||||
/**
|
||||
* 将array的内容引用复制给本对象
|
||||
*
|
||||
* @param array
|
||||
* @param array ByteArray
|
||||
*/
|
||||
public void directFrom(ByteArray array) {
|
||||
if (array != null) {
|
||||
@@ -115,7 +115,7 @@ public final class ByteArray {
|
||||
/**
|
||||
* 将本对象的内容引用复制给array
|
||||
*
|
||||
* @param array
|
||||
* @param array ByteArray
|
||||
*/
|
||||
public void directTo(ByteArray array) {
|
||||
if (array != null) {
|
||||
@@ -270,8 +270,8 @@ public final class ByteArray {
|
||||
/**
|
||||
* 写入ByteBuffer指定长度的数据
|
||||
*
|
||||
* @param buffer
|
||||
* @param len
|
||||
* @param buffer 数据
|
||||
* @param len 指定长度
|
||||
*/
|
||||
public void write(ByteBuffer buffer, int len) {
|
||||
if (len < 1) return;
|
||||
@@ -294,7 +294,7 @@ public final class ByteArray {
|
||||
*
|
||||
* @param charset 字符集
|
||||
*
|
||||
* @return
|
||||
* @return 字符串
|
||||
*/
|
||||
public String toString(final Charset charset) {
|
||||
return toString(0, count, charset);
|
||||
@@ -305,7 +305,7 @@ public final class ByteArray {
|
||||
*
|
||||
* @param charset 字符集
|
||||
*
|
||||
* @return
|
||||
* @return 字符串
|
||||
*/
|
||||
public String toStringAndClear(final Charset charset) {
|
||||
String str = toString(0, count, charset);
|
||||
@@ -320,7 +320,7 @@ public final class ByteArray {
|
||||
* @param len 长度
|
||||
* @param charset 字符集
|
||||
*
|
||||
* @return
|
||||
* @return 字符串
|
||||
*/
|
||||
public String toString(final int offset, int len, final Charset charset) {
|
||||
if (charset == null) return new String(Utility.decodeUTF8(content, offset, len));
|
||||
@@ -334,7 +334,7 @@ public final class ByteArray {
|
||||
* @param len 长度
|
||||
* @param charset 字符集
|
||||
*
|
||||
* @return
|
||||
* @return 字符串
|
||||
*/
|
||||
public String toDecodeString(final int offset, int len, final Charset charset) {
|
||||
int index = offset;
|
||||
|
||||
@@ -3,23 +3,25 @@
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.service;
|
||||
package org.redkale.util;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* SNCP协议中用于CompletionHandler回调函数中的attach字段。
|
||||
* 标记注释,备注
|
||||
*
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
* <p> 详情见: http://redkale.org
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({PARAMETER})
|
||||
@Target({TYPE, METHOD, FIELD, PARAMETER})
|
||||
@Retention(RUNTIME)
|
||||
public @interface DynAttachment {
|
||||
public @interface Comment {
|
||||
|
||||
String value();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.redkale.util;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.*;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
@@ -15,9 +15,10 @@ import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
* @param <D> 目标对象的数据类型
|
||||
* @param <S> 源对象的数据类型
|
||||
*/
|
||||
public interface Reproduce<D, S> {
|
||||
public interface Reproduce<D, S> extends BiFunction<D, S, D>{
|
||||
|
||||
public D copy(D dest, S src);
|
||||
@Override
|
||||
public D apply(D dest, S src);
|
||||
|
||||
public static <D, S> Reproduce<D, S> create(final Class<D> destClass, final Class<S> srcClass) {
|
||||
return create(destClass, srcClass, null);
|
||||
@@ -59,7 +60,7 @@ public interface Reproduce<D, S> {
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = (cw.visitMethod(ACC_PUBLIC, "copy", "(" + destDesc + srcDesc + ")" + destDesc, null, null));
|
||||
mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + destDesc + srcDesc + ")" + destDesc, null, null));
|
||||
//mv.setDebug(true);
|
||||
|
||||
for (java.lang.reflect.Field field : srcClass.getFields()) {
|
||||
@@ -112,14 +113,14 @@ public interface Reproduce<D, S> {
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = (cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "copy", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null));
|
||||
mv = (cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null));
|
||||
//mv.setDebug(true);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitTypeInsn(CHECKCAST, destName);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitTypeInsn(CHECKCAST, srcName);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "copy", "(" + destDesc + srcDesc + ")" + destDesc, false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(" + destDesc + srcDesc + ")" + destDesc, false);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
|
||||
@@ -15,6 +15,9 @@ import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 如果Resource(name = "$") 表示资源name采用所属对象的name
|
||||
* name规则:
|
||||
* 1: "$"有特殊含义, 不能表示"$"资源本身
|
||||
* 2: 只能是字母、数字、(短横)-、(下划线)_、点(.)的组合
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
@@ -51,6 +54,12 @@ public final class ResourceFactory {
|
||||
this.store.clear();
|
||||
}
|
||||
|
||||
public void checkName(String name) {
|
||||
if (name == null || (!name.isEmpty() && !name.matches("^[a-zA-Z0-9_\\-\\.\\[\\]\\(\\)]+$"))) {
|
||||
throw new IllegalArgumentException("Resource.name(" + name + ") contains illegal character, must be (a-z,A-Z,0-9,_,.,(,),-,[,])");
|
||||
}
|
||||
}
|
||||
|
||||
public <A> A register(final Class<? extends A> clazz, final A rs) {
|
||||
return register(true, clazz, rs);
|
||||
}
|
||||
@@ -141,6 +150,7 @@ public final class ResourceFactory {
|
||||
}
|
||||
|
||||
public <A> A register(final boolean autoSync, final String name, final A rs) {
|
||||
checkName(name);
|
||||
final Class<?> claz = rs.getClass();
|
||||
ResourceType rtype = claz.getAnnotation(ResourceType.class);
|
||||
if (rtype == null) {
|
||||
@@ -164,13 +174,17 @@ public final class ResourceFactory {
|
||||
}
|
||||
|
||||
public <A> A register(final boolean autoSync, final String name, final Type clazz, final A rs) {
|
||||
checkName(name);
|
||||
ConcurrentHashMap<String, ResourceEntry> map = this.store.get(clazz);
|
||||
if (map == null) {
|
||||
ConcurrentHashMap<String, ResourceEntry> sub = new ConcurrentHashMap();
|
||||
sub.put(name, new ResourceEntry(rs));
|
||||
store.put(clazz, sub);
|
||||
return null;
|
||||
} else {
|
||||
synchronized (clazz) {
|
||||
map = this.store.get(clazz);
|
||||
if (map == null) {
|
||||
map = new ConcurrentHashMap();
|
||||
store.put(clazz, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
ResourceEntry re = map.get(name);
|
||||
if (re == null) {
|
||||
map.put(name, new ResourceEntry(rs));
|
||||
@@ -179,7 +193,6 @@ public final class ResourceFactory {
|
||||
}
|
||||
return re == null ? null : (A) re.value;
|
||||
}
|
||||
}
|
||||
|
||||
public <A> A find(Class<? extends A> clazz) {
|
||||
return find("", clazz);
|
||||
|
||||
@@ -84,6 +84,10 @@ public final class Utility {
|
||||
private Utility() {
|
||||
}
|
||||
|
||||
public static String uuid() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
public static String now() {
|
||||
return String.format(format, System.currentTimeMillis());
|
||||
}
|
||||
@@ -183,6 +187,19 @@ public final class Utility {
|
||||
return today.getYear() * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定时间的20160202格式的int值
|
||||
*
|
||||
* @param time 指定时间
|
||||
*
|
||||
* @return 毫秒数
|
||||
*/
|
||||
public static int yyyyMMdd(long time) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTimeInMillis(time);
|
||||
return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间点所在星期的周一
|
||||
*
|
||||
@@ -621,7 +638,7 @@ public final class Utility {
|
||||
conn.disconnect();
|
||||
return remoteHttpContent(ctx, method, newurl, headers, body);
|
||||
}
|
||||
InputStream in = rs < 400 ? conn.getInputStream() : conn.getErrorStream();
|
||||
InputStream in = rs < 400 || rs == 404 ? conn.getInputStream() : conn.getErrorStream();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||
byte[] bytes = new byte[1024];
|
||||
int pos;
|
||||
@@ -645,4 +662,33 @@ public final class Utility {
|
||||
}
|
||||
return charsetName == null ? out.toString() : out.toString(charsetName);
|
||||
}
|
||||
|
||||
public static ByteArrayOutputStream readStream(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||
byte[] bytes = new byte[1024];
|
||||
int pos;
|
||||
while ((pos = in.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, pos);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public static byte[] readBytes(InputStream in) throws IOException {
|
||||
return readStream(in).toByteArray();
|
||||
}
|
||||
|
||||
public static ByteArrayOutputStream readStreamThenClose(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||
byte[] bytes = new byte[1024];
|
||||
int pos;
|
||||
while ((pos = in.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, pos);
|
||||
}
|
||||
in.close();
|
||||
return out;
|
||||
}
|
||||
|
||||
public static byte[] readBytesThenClose(InputStream in) throws IOException {
|
||||
return readStreamThenClose(in).toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* RedKale工具包
|
||||
* Redkale工具包
|
||||
*/
|
||||
package org.redkale.util;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* 提供RedKale服务的监控、动态部署、数据收集功能
|
||||
* 提供Redkale服务的监控、动态部署、数据收集功能
|
||||
*/
|
||||
package org.redkale.watch;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.redkale.test.http;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.*;
|
||||
import java.nio.charset.*;
|
||||
import java.util.*;
|
||||
@@ -18,24 +19,6 @@ import org.redkale.net.http.*;
|
||||
*/
|
||||
public interface HttpRequestDesc {
|
||||
|
||||
//获取请求方法 GET、POST等
|
||||
public String getMethod();
|
||||
|
||||
//获取协议名 http、https、ws、wss等
|
||||
public String getProtocol();
|
||||
|
||||
//获取Host的Header值
|
||||
public String getHost();
|
||||
|
||||
//获取请求内容的长度, 为-1表示内容长度不确定
|
||||
public long getContentLength();
|
||||
|
||||
//获取Content-Type的header值
|
||||
public String getContentType();
|
||||
|
||||
//获取Connection的Header值
|
||||
public String getConnection();
|
||||
|
||||
//获取客户端地址IP
|
||||
public SocketAddress getRemoteAddress();
|
||||
|
||||
@@ -67,11 +50,29 @@ public interface HttpRequestDesc {
|
||||
//获取所有Cookie对象
|
||||
public java.net.HttpCookie[] getCookies();
|
||||
|
||||
//获取Cookie值
|
||||
public String getCookie(String name);
|
||||
|
||||
//获取Cookie值, 没有返回默认值
|
||||
public String getCookie(String name, String defaultValue);
|
||||
|
||||
//获取Cookie值
|
||||
public String getCookie(String name);
|
||||
//获取协议名 http、https、ws、wss等
|
||||
public String getProtocol();
|
||||
|
||||
//获取请求方法 GET、POST等
|
||||
public String getMethod();
|
||||
|
||||
//获取Content-Type的header值
|
||||
public String getContentType();
|
||||
|
||||
//获取请求内容的长度, 为-1表示内容长度不确定
|
||||
public long getContentLength();
|
||||
|
||||
//获取Connection的Header值
|
||||
public String getConnection();
|
||||
|
||||
//获取Host的Header值
|
||||
public String getHost();
|
||||
|
||||
//获取请求的URL
|
||||
public String getRequestURI();
|
||||
@@ -82,17 +83,6 @@ public interface HttpRequestDesc {
|
||||
//从prefix之后截取getRequestURI再对"/"进行分隔
|
||||
public String[] getRequstURIPaths(String prefix);
|
||||
|
||||
//获取请求URL分段中含prefix段的long值
|
||||
// 例如请求URL /pipes/record/query/time:1453104341363/id:40
|
||||
// 获取time参数: long time = request.getRequstURIPath("time:", 0L);
|
||||
public long getRequstURIPath(String prefix, long defaultValue);
|
||||
|
||||
//获取请求URL分段中含prefix段的int值
|
||||
// 例如请求URL /pipes/record/query/offset:2/limit:50
|
||||
// 获取page参数: int offset = request.getRequstURIPath("offset:", 1);
|
||||
// 获取size参数: int limit = request.getRequstURIPath("limit:", 20);
|
||||
public int getRequstURIPath(String prefix, int defaultValue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的值
|
||||
// 例如请求URL /pipes/record/query/name:hello
|
||||
// 获取name参数: String name = request.getRequstURIPath("name:", "none");
|
||||
@@ -103,6 +93,43 @@ public interface HttpRequestDesc {
|
||||
// 获取type参数: short type = request.getRequstURIPath("type:", (short)0);
|
||||
public short getRequstURIPath(String prefix, short defaultValue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的short值
|
||||
// 例如请求URL /pipes/record/query/type:a
|
||||
// 获取type参数: short type = request.getRequstURIPath(16, "type:", (short)0); type = 10
|
||||
public short getRequstURIPath(int radix, String prefix, short defvalue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的int值
|
||||
// 例如请求URL /pipes/record/query/offset:2/limit:50
|
||||
// 获取offset参数: int offset = request.getRequstURIPath("offset:", 1);
|
||||
// 获取limit参数: int limit = request.getRequstURIPath("limit:", 20);
|
||||
public int getRequstURIPath(String prefix, int defaultValue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的int值
|
||||
// 例如请求URL /pipes/record/query/offset:2/limit:10
|
||||
// 获取offset参数: int offset = request.getRequstURIPath("offset:", 1);
|
||||
// 获取limit参数: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16
|
||||
public int getRequstURIPath(int radix, String prefix, int defaultValue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的float值
|
||||
// 例如请求URL /pipes/record/query/point:40.0
|
||||
// 获取time参数: float point = request.getRequstURIPath("point:", 0.0f);
|
||||
public float getRequstURIPath(String prefix, float defvalue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的long值
|
||||
// 例如请求URL /pipes/record/query/time:1453104341363/id:40
|
||||
// 获取time参数: long time = request.getRequstURIPath("time:", 0L);
|
||||
public long getRequstURIPath(String prefix, long defaultValue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的long值
|
||||
// 例如请求URL /pipes/record/query/time:1453104341363/id:40
|
||||
// 获取time参数: long time = request.getRequstURIPath("time:", 0L);
|
||||
public long getRequstURIPath(int radix, String prefix, long defvalue);
|
||||
|
||||
// 获取请求URL分段中含prefix段的double值 <br>
|
||||
// 例如请求URL /pipes/record/query/point:40.0 <br>
|
||||
// 获取time参数: double point = request.getRequstURIPath("point:", 0.0);
|
||||
public double getRequstURIPath(String prefix, double defvalue);
|
||||
|
||||
//获取所有的header名
|
||||
public String[] getHeaderNames();
|
||||
|
||||
@@ -113,10 +140,10 @@ public interface HttpRequestDesc {
|
||||
public String getHeader(String name, String defaultValue);
|
||||
|
||||
//获取指定的header的json值
|
||||
public <T> T getJsonHeader(JsonConvert convert, Class<T> clazz, String name);
|
||||
public <T> T getJsonHeader(Type type, String name);
|
||||
|
||||
//获取指定的header的json值
|
||||
public <T> T getJsonHeader(Class<T> clazz, String name);
|
||||
public <T> T getJsonHeader(JsonConvert convert, Type type, String name);
|
||||
|
||||
//获取指定的header的boolean值, 没有返回默认boolean值
|
||||
public boolean getBooleanHeader(String name, boolean defaultValue);
|
||||
@@ -124,15 +151,30 @@ public interface HttpRequestDesc {
|
||||
// 获取指定的header的short值, 没有返回默认short值
|
||||
public short getShortHeader(String name, short defaultValue);
|
||||
|
||||
// 获取指定的header的short值, 没有返回默认short值
|
||||
public short getShortHeader(int radix, String name, short defaultValue);
|
||||
|
||||
// 获取指定的header的short值, 没有返回默认short值
|
||||
public short getShortHeader(String name, int defaultValue);
|
||||
|
||||
// 获取指定的header的short值, 没有返回默认short值
|
||||
public short getShortHeader(int radix, String name, int defaultValue);
|
||||
|
||||
//获取指定的header的int值, 没有返回默认int值
|
||||
public int getIntHeader(String name, int defaultValue);
|
||||
|
||||
// 获取指定的header的float值, 没有返回默认float值
|
||||
public float getFloatHeader(String name, float defaultValue);
|
||||
//获取指定的header的int值, 没有返回默认int值
|
||||
public int getIntHeader(int radix, String name, int defaultValue);
|
||||
|
||||
// 获取指定的header的long值, 没有返回默认long值
|
||||
public long getLongHeader(String name, long defaultValue);
|
||||
|
||||
// 获取指定的header的long值, 没有返回默认long值
|
||||
public long getLongHeader(int radix, String name, long defaultValue);
|
||||
|
||||
// 获取指定的header的float值, 没有返回默认float值
|
||||
public float getFloatHeader(String name, float defaultValue);
|
||||
|
||||
//获取指定的header的double值, 没有返回默认double值
|
||||
public double getDoubleHeader(String name, double defaultValue);
|
||||
|
||||
@@ -146,10 +188,10 @@ public interface HttpRequestDesc {
|
||||
public String getParameter(String name, String defaultValue);
|
||||
|
||||
//获取指定的参数json值
|
||||
public <T> T getJsonParameter(JsonConvert convert, Class<T> clazz, String name);
|
||||
public <T> T getJsonParameter(Type type, String name);
|
||||
|
||||
//获取指定的参数json值
|
||||
public <T> T getJsonParameter(Class<T> clazz, String name);
|
||||
public <T> T getJsonParameter(JsonConvert convert, Type type, String name);
|
||||
|
||||
//获取指定的参数boolean值, 没有返回默认boolean值
|
||||
public boolean getBooleanParameter(String name, boolean defaultValue);
|
||||
@@ -157,18 +199,47 @@ public interface HttpRequestDesc {
|
||||
//获取指定的参数short值, 没有返回默认short值
|
||||
public short getShortParameter(String name, short defaultValue);
|
||||
|
||||
//获取指定的参数short值, 没有返回默认short值
|
||||
public short getShortParameter(int radix, String name, short defaultValue);
|
||||
|
||||
//获取指定的参数short值, 没有返回默认short值
|
||||
public short getShortParameter(int radix, String name, int defaultValue);
|
||||
|
||||
//获取指定的参数int值, 没有返回默认int值
|
||||
public int getIntParameter(String name, int defaultValue);
|
||||
|
||||
//获取指定的参数float值, 没有返回默认float值
|
||||
public float getFloatParameter(String name, float defaultValue);
|
||||
//获取指定的参数int值, 没有返回默认int值
|
||||
public int getIntParameter(int radix, String name, int defaultValue);
|
||||
|
||||
//获取指定的参数long值, 没有返回默认long值
|
||||
public long getLongParameter(String name, long defaultValue);
|
||||
|
||||
//获取指定的参数long值, 没有返回默认long值
|
||||
public long getLongParameter(int radix, String name, long defaultValue);
|
||||
|
||||
//获取指定的参数float值, 没有返回默认float值
|
||||
public float getFloatParameter(String name, float defaultValue);
|
||||
|
||||
//获取指定的参数double值, 没有返回默认double值
|
||||
public double getDoubleParameter(String name, double defaultValue);
|
||||
|
||||
//获取翻页对象 同 getFlipper("flipper", false, 0);
|
||||
public org.redkale.source.Flipper getFlipper();
|
||||
|
||||
//获取翻页对象 同 getFlipper("flipper", needcreate, 0);
|
||||
public org.redkale.source.Flipper getFlipper(boolean needcreate);
|
||||
|
||||
//获取翻页对象 同 getFlipper("flipper", false, maxLimit);
|
||||
public org.redkale.source.Flipper getFlipper(int maxLimit);
|
||||
|
||||
//获取翻页对象 同 getFlipper("flipper", needcreate, maxLimit)
|
||||
public org.redkale.source.Flipper getFlipper(boolean needcreate, int maxLimit);
|
||||
|
||||
//获取翻页对象 http://redkale.org/pipes/records/list/offset:0/limit:20/sort:createtime%20ASC
|
||||
//http://redkale.org/pipes/records/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'}
|
||||
//以上两种接口都可以获取到翻页对象
|
||||
public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit);
|
||||
|
||||
//获取HTTP上下文对象
|
||||
public HttpContext getContext();
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@ import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import org.redkale.convert.json.*;
|
||||
import org.redkale.net.http.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -18,6 +21,12 @@ import org.redkale.convert.json.*;
|
||||
*/
|
||||
public interface HttpResponseDesc {
|
||||
|
||||
//增加Cookie值
|
||||
public HttpResponse addCookie(HttpCookie... cookies);
|
||||
|
||||
//增加Cookie值
|
||||
public HttpResponse addCookie(Collection<HttpCookie> cookies);
|
||||
|
||||
//设置状态码
|
||||
public void setStatus(int status);
|
||||
|
||||
@@ -28,26 +37,26 @@ public interface HttpResponseDesc {
|
||||
public String getContentType();
|
||||
|
||||
//设置 ContentType
|
||||
public void setContentType(String contentType);
|
||||
public HttpResponse setContentType(String contentType);
|
||||
|
||||
//获取内容长度
|
||||
public long getContentLength();
|
||||
|
||||
//设置内容长度
|
||||
public void setContentLength(long contentLength);
|
||||
public HttpResponse setContentLength(long contentLength);
|
||||
|
||||
//设置Header值
|
||||
public void setHeader(String name, Object value);
|
||||
public HttpResponse setHeader(String name, Object value);
|
||||
|
||||
//添加Header值
|
||||
public void addHeader(String name, Object value);
|
||||
public HttpResponse addHeader(String name, Object value);
|
||||
|
||||
//添加Header值
|
||||
public HttpResponse addHeader(Map<String, ?> map);
|
||||
|
||||
//跳过header的输出
|
||||
//通常应用场景是,调用者的输出内容里已经包含了HTTP的响应头信息,因此需要调用此方法避免重复输出HTTP响应头信息。
|
||||
public void skipHeader();
|
||||
|
||||
//增加Cookie值
|
||||
public void addCookie(HttpCookie... cookies);
|
||||
public HttpResponse skipHeader();
|
||||
|
||||
//异步输出指定内容
|
||||
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler);
|
||||
@@ -73,6 +82,18 @@ public interface HttpResponseDesc {
|
||||
//将对象以JSON格式输出
|
||||
public void finishJson(final Object... objs);
|
||||
|
||||
//将RetResult对象以JSON格式输出
|
||||
public void finishJson(final org.redkale.service.RetResult ret);
|
||||
|
||||
//将RetResult对象以JSON格式输出
|
||||
public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret);
|
||||
|
||||
//将对象以JavaScript格式输出
|
||||
public void finishJsResult(String var, Object result);
|
||||
|
||||
//将对象以JavaScript格式输出
|
||||
public void finishJsResult(JsonConvert jsonConvert, String var, Object result);
|
||||
|
||||
//将指定字符串以响应结果输出
|
||||
public void finish(String obj);
|
||||
|
||||
@@ -102,4 +123,10 @@ public interface HttpResponseDesc {
|
||||
//将指定文件按响应结果输出
|
||||
public void finish(File file) throws IOException;
|
||||
|
||||
//将文件按指定文件名输出
|
||||
public void finish(final String filename, File file) throws IOException;
|
||||
|
||||
//HttpResponse回收时回调的监听方法
|
||||
public void setRecycleListener(BiConsumer<HttpRequest, HttpResponse> recycleListener);
|
||||
|
||||
}
|
||||
|
||||
35
test/org/redkale/test/rest/HelloBean.java
Normal file
35
test/org/redkale/test/rest/HelloBean.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package org.redkale.test.rest;
|
||||
|
||||
import org.redkale.convert.json.JsonFactory;
|
||||
import org.redkale.net.http.*;
|
||||
import org.redkale.source.FilterBean;
|
||||
|
||||
public class HelloBean implements FilterBean {
|
||||
|
||||
private int helloid;
|
||||
|
||||
@RestHeader(name = "hello-res")
|
||||
private String res;
|
||||
|
||||
public int getHelloid() {
|
||||
return helloid;
|
||||
}
|
||||
|
||||
public void setHelloid(int helloid) {
|
||||
this.helloid = helloid;
|
||||
}
|
||||
|
||||
public String getRes() {
|
||||
return res;
|
||||
}
|
||||
|
||||
public void setRes(String res) {
|
||||
this.res = res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonFactory.root().getConvert().convertTo(this);
|
||||
}
|
||||
|
||||
}
|
||||
88
test/org/redkale/test/rest/HelloEntity.java
Normal file
88
test/org/redkale/test/rest/HelloEntity.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package org.redkale.test.rest;
|
||||
|
||||
import javax.persistence.Id;
|
||||
import org.redkale.convert.json.JsonFactory;
|
||||
import org.redkale.net.http.*;
|
||||
import org.redkale.source.VirtualEntity;
|
||||
|
||||
@VirtualEntity
|
||||
public class HelloEntity {
|
||||
|
||||
@Id
|
||||
private int helloid;
|
||||
|
||||
private String helloname;
|
||||
|
||||
private int creator;
|
||||
|
||||
private long updatetime;
|
||||
|
||||
private long createtime;
|
||||
|
||||
@RestHeader(name = "hello-res")
|
||||
private String resname;
|
||||
|
||||
@RestAddress
|
||||
private String clientaddr;
|
||||
|
||||
public int getHelloid() {
|
||||
return helloid;
|
||||
}
|
||||
|
||||
public void setHelloid(int helloid) {
|
||||
this.helloid = helloid;
|
||||
}
|
||||
|
||||
public String getHelloname() {
|
||||
return helloname;
|
||||
}
|
||||
|
||||
public void setHelloname(String helloname) {
|
||||
this.helloname = helloname;
|
||||
}
|
||||
|
||||
public long getUpdatetime() {
|
||||
return updatetime;
|
||||
}
|
||||
|
||||
public void setUpdatetime(long updatetime) {
|
||||
this.updatetime = updatetime;
|
||||
}
|
||||
|
||||
public long getCreatetime() {
|
||||
return createtime;
|
||||
}
|
||||
|
||||
public void setCreatetime(long createtime) {
|
||||
this.createtime = createtime;
|
||||
}
|
||||
|
||||
public int getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public void setCreator(int creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public String getClientaddr() {
|
||||
return clientaddr;
|
||||
}
|
||||
|
||||
public void setClientaddr(String clientaddr) {
|
||||
this.clientaddr = clientaddr;
|
||||
}
|
||||
|
||||
public String getResname() {
|
||||
return resname;
|
||||
}
|
||||
|
||||
public void setResname(String resname) {
|
||||
this.resname = resname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonFactory.root().getConvert().convertTo(this);
|
||||
}
|
||||
}
|
||||
79
test/org/redkale/test/rest/HelloService.java
Normal file
79
test/org/redkale/test/rest/HelloService.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package org.redkale.test.rest;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import org.redkale.net.http.*;
|
||||
|
||||
import org.redkale.service.*;
|
||||
import org.redkale.source.DataSource;
|
||||
import org.redkale.source.Flipper;
|
||||
import org.redkale.util.Sheet;
|
||||
|
||||
/**
|
||||
* 类说明:
|
||||
* Flipper : Source组件中的翻页对象
|
||||
* UserInfo :当前用户类
|
||||
* HelloEntity: Hello模块的实体类
|
||||
* HelloBean: Hellow模块实现FilterBean的过滤Bean类
|
||||
*
|
||||
*/
|
||||
public class HelloService implements Service {
|
||||
|
||||
private int nodeid;
|
||||
|
||||
@Resource
|
||||
private DataSource source;
|
||||
|
||||
public HelloService() {
|
||||
}
|
||||
|
||||
public HelloService(int nodeid) {
|
||||
this.nodeid = nodeid;
|
||||
}
|
||||
|
||||
//增加记录
|
||||
public RetResult<HelloEntity> createHello(UserInfo info, HelloEntity entity) {
|
||||
entity.setCreator(info == null ? 0 : info.getUserid()); //设置当前用户ID
|
||||
entity.setCreatetime(System.currentTimeMillis());
|
||||
source.insert(entity);
|
||||
return new RetResult<>(entity);
|
||||
}
|
||||
|
||||
//删除记录
|
||||
public void deleteHello(int id) { //通过 /hello/delete/1234 删除对象
|
||||
source.delete(HelloEntity.class, id);
|
||||
}
|
||||
|
||||
//修改记录
|
||||
public void updateHello(@RestAddress String clientAddr, HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
|
||||
System.out.println("修改记录-" + nodeid + ": clientAddr = " + clientAddr + ", entity =" + entity);
|
||||
if (entity != null) entity.setUpdatetime(System.currentTimeMillis());
|
||||
if (source != null) source.update(entity);
|
||||
}
|
||||
|
||||
//修改记录
|
||||
@RestMapping(name = "partupdate")
|
||||
public void updateHello(HelloEntity entity, @RestParam(name = "cols") String[] columns) { //通过 /hello/partupdate?bean={...} 修改对象
|
||||
entity.setUpdatetime(System.currentTimeMillis());
|
||||
source.updateColumns(entity, columns);
|
||||
}
|
||||
|
||||
//查询Sheet列表
|
||||
public Sheet<HelloEntity> queryHello(HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询Sheet列表
|
||||
return source.querySheet(HelloEntity.class, flipper, bean);
|
||||
}
|
||||
|
||||
//查询List列表
|
||||
@RestMapping(name = "list")
|
||||
public List<HelloEntity> queryHello(HelloBean bean) { //通过 /hello/list?bean={...} 查询List列表
|
||||
return source.queryList(HelloEntity.class, bean);
|
||||
}
|
||||
|
||||
//查询单个
|
||||
@RestMapping(name = "find")
|
||||
@RestMapping(name = "jsfind", jsvar = "varhello")
|
||||
public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /hello/find/1234 查询对象
|
||||
return source.find(HelloEntity.class, id);
|
||||
}
|
||||
|
||||
}
|
||||
61
test/org/redkale/test/rest/HelloService2.java
Normal file
61
test/org/redkale/test/rest/HelloService2.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.test.rest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.redkale.net.http.*;
|
||||
import org.redkale.service.*;
|
||||
import org.redkale.source.*;
|
||||
import org.redkale.util.Sheet;
|
||||
|
||||
/**
|
||||
* 类说明:
|
||||
* Flipper : Source组件中的翻页对象
|
||||
* UserInfo :当前用户类
|
||||
* HelloEntity: Hello模块的实体类
|
||||
* HelloBean: Hellow模块实现FilterBean的过滤Bean类
|
||||
*
|
||||
*/
|
||||
@RestService(name = "hello", moduleid = 0, repair = true, ignore = false)
|
||||
public class HelloService2 implements Service {
|
||||
|
||||
@Resource
|
||||
private DataSource source;
|
||||
|
||||
//增加记录
|
||||
@RestMapping(name = "create", auth = false)
|
||||
public RetResult<HelloEntity> createHello(UserInfo info, @RestParam(name = "bean") HelloEntity entity) {
|
||||
entity.setCreator(info == null ? 0 : info.getUserid()); //设置当前用户ID
|
||||
entity.setCreatetime(System.currentTimeMillis());
|
||||
source.insert(entity);
|
||||
return new RetResult<>(entity);
|
||||
}
|
||||
|
||||
//删除记录
|
||||
@RestMapping(name = "delete", auth = false)
|
||||
public void deleteHello(@RestParam(name = "#") int id) { //通过 /hello/delete/1234 删除对象
|
||||
source.delete(HelloEntity.class, id);
|
||||
}
|
||||
|
||||
//修改记录
|
||||
@RestMapping(name = "update", auth = false)
|
||||
public void updateHello(@RestParam(name = "bean") HelloEntity entity) { //通过 /hello/update?bean={...} 修改对象
|
||||
entity.setUpdatetime(System.currentTimeMillis());
|
||||
source.update(entity);
|
||||
}
|
||||
|
||||
//查询列表
|
||||
@RestMapping(name = "query", auth = false)
|
||||
public Sheet<HelloEntity> queryHello(@RestParam(name = "bean") HelloBean bean, Flipper flipper) { //通过 /hello/query/offset:0/limit:20?bean={...} 查询列表
|
||||
return source.querySheet(HelloEntity.class, flipper, bean);
|
||||
}
|
||||
|
||||
//查询单个
|
||||
@RestMapping(name = "find", auth = false)
|
||||
public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /hello/find/1234 查询对象
|
||||
return source.find(HelloEntity.class, id);
|
||||
}
|
||||
}
|
||||
163
test/org/redkale/test/rest/RetCodes.java
Normal file
163
test/org/redkale/test/rest/RetCodes.java
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.test.rest;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import org.redkale.service.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public abstract class RetCodes {
|
||||
|
||||
protected static final Map<Integer, String> rets = new HashMap<>();
|
||||
|
||||
|
||||
protected RetCodes() {
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
protected static void load(Class clazz) {
|
||||
for (Field field : clazz.getFields()) {
|
||||
if (!Modifier.isStatic(field.getModifiers())) continue;
|
||||
if (field.getType() != int.class) continue;
|
||||
RetLabel info = field.getAnnotation(RetLabel.class);
|
||||
if (info == null) continue;
|
||||
int value;
|
||||
try {
|
||||
value = field.getInt(null);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
rets.put(value, info.value());
|
||||
}
|
||||
}
|
||||
|
||||
public static RetResult retResult(int retcode) {
|
||||
if (retcode == 0) return RetResult.success();
|
||||
return new RetResult(retcode, retInfo(retcode));
|
||||
}
|
||||
|
||||
public static String retInfo(int retcode) {
|
||||
if (retcode == 0) return "成功";
|
||||
return rets.getOrDefault(retcode, "未知错误");
|
||||
}
|
||||
|
||||
//2000_0001 - 2999_9999 预留给 Redkale的扩展包redkalex使用
|
||||
//3000_0001 - 7999_9999 为平台系统使用
|
||||
//8000_0001 - 9999_9999 为OSS系统使用
|
||||
//------------------------------------- 通用模块 -----------------------------------------
|
||||
@RetLabel("参数无效")
|
||||
public static final int RET_PARAMS_ILLEGAL = 30010001;
|
||||
|
||||
@RetLabel("无上传文件")
|
||||
public static final int RET_UPLOAD_NOFILE = 30010002;
|
||||
|
||||
@RetLabel("上传文件过大")
|
||||
public static final int RET_UPLOAD_FILETOOBIG = 30010003;
|
||||
|
||||
@RetLabel("上传文件不是图片")
|
||||
public static final int RET_UPLOAD_NOTIMAGE = 30010004;
|
||||
|
||||
//------------------------------------- 用户模块 -----------------------------------------
|
||||
@RetLabel("未登陆")
|
||||
public static final int RET_USER_UNLOGIN = 30020001;
|
||||
|
||||
@RetLabel("用户登录失败")
|
||||
public static final int RET_USER_LOGIN_FAIL = 30020002;
|
||||
|
||||
@RetLabel("用户或密码错误")
|
||||
public static final int RET_USER_ACCOUNT_PWD_ILLEGAL = 30020003;
|
||||
|
||||
@RetLabel("密码设置无效")
|
||||
public static final int RET_USER_PASSWORD_ILLEGAL = 30020004;
|
||||
|
||||
@RetLabel("用户被禁用")
|
||||
public static final int RET_USER_FREEZED = 30020005;
|
||||
|
||||
@RetLabel("用户权限不够")
|
||||
public static final int RET_USER_AUTH_ILLEGAL = 30020006;
|
||||
|
||||
@RetLabel("用户不存在")
|
||||
public static final int RET_USER_NOTEXISTS = 30020007;
|
||||
|
||||
@RetLabel("用户状态异常")
|
||||
public static final int RET_USER_STATUS_ILLEGAL = 30020008;
|
||||
|
||||
@RetLabel("用户注册参数无效")
|
||||
public static final int RET_USER_SIGNUP_ILLEGAL = 30020009;
|
||||
|
||||
@RetLabel("用户性别参数无效")
|
||||
public static final int RET_USER_GENDER_ILLEGAL = 30020010;
|
||||
|
||||
@RetLabel("用户名无效")
|
||||
public static final int RET_USER_USERNAME_ILLEGAL = 30020011;
|
||||
|
||||
@RetLabel("用户账号无效")
|
||||
public static final int RET_USER_ACCOUNT_ILLEGAL = 30020012;
|
||||
|
||||
@RetLabel("用户账号已存在")
|
||||
public static final int RET_USER_ACCOUNT_EXISTS = 30020013;
|
||||
|
||||
@RetLabel("手机号码无效")
|
||||
public static final int RET_USER_MOBILE_ILLEGAL = 30020014;
|
||||
|
||||
@RetLabel("手机号码已存在")
|
||||
public static final int RET_USER_MOBILE_EXISTS = 30020015;
|
||||
|
||||
@RetLabel("手机验证码发送过于频繁")
|
||||
public static final int RET_USER_MOBILE_SMSFREQUENT = 30020016;
|
||||
|
||||
@RetLabel("邮箱地址无效")
|
||||
public static final int RET_USER_EMAIL_ILLEGAL = 30020017;
|
||||
|
||||
@RetLabel("邮箱地址已存在")
|
||||
public static final int RET_USER_EMAIL_EXISTS = 30020018;
|
||||
|
||||
@RetLabel("微信绑定号无效")
|
||||
public static final int RET_USER_WXID_ILLEGAL = 30020019;
|
||||
|
||||
@RetLabel("微信绑定号已存在")
|
||||
public static final int RET_USER_WXID_EXISTS = 30020020;
|
||||
|
||||
@RetLabel("绑定微信号失败")
|
||||
public static final int RET_USER_WXID_BIND_FAIL = 30020021;
|
||||
|
||||
@RetLabel("QQ绑定号无效")
|
||||
public static final int RET_USER_QQID_ILLEGAL = 30020022;
|
||||
|
||||
@RetLabel("QQ绑定号已存在")
|
||||
public static final int RET_USER_QQID_EXISTS = 30020023;
|
||||
|
||||
@RetLabel("绑定QQ号失败")
|
||||
public static final int RET_USER_QQID_BIND_FAIL = 30020024;
|
||||
|
||||
@RetLabel("获取绑定QQ信息失败")
|
||||
public static final int RET_USER_QQID_INFO_FAIL = 30020025;
|
||||
|
||||
@RetLabel("验证码无效")
|
||||
public static final int RET_USER_RANDCODE_ILLEGAL = 30020026; //邮件或者短信验证码
|
||||
|
||||
@RetLabel("验证码已过期")
|
||||
public static final int RET_USER_RANDCODE_EXPIRED = 30020027; //邮件或者短信验证码
|
||||
|
||||
@RetLabel("验证码错误或失效")
|
||||
public static final int RET_USER_CAPTCHA_ILLEGAL = 30020028; //图片验证码
|
||||
|
||||
@RetLabel("用户类型无效")
|
||||
public static final int RET_USER_TYPE_ILLEGAL = 30020029;
|
||||
|
||||
@RetLabel("用户设备ID无效")
|
||||
public static final int RET_USER_APPTOKEN_ILLEGAL = 30020030;
|
||||
|
||||
|
||||
static {
|
||||
load(RetCodes.class);
|
||||
}
|
||||
}
|
||||
41
test/org/redkale/test/rest/SimpleRestServlet.java
Normal file
41
test/org/redkale/test/rest/SimpleRestServlet.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package org.redkale.test.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.redkale.net.http.*;
|
||||
import org.redkale.service.RetResult;
|
||||
|
||||
|
||||
public class SimpleRestServlet extends RestHttpServlet<UserInfo> {
|
||||
|
||||
protected static final RetResult RET_UNLOGIN = RetCodes.retResult(RetCodes.RET_USER_UNLOGIN);
|
||||
|
||||
protected static final RetResult RET_AUTHILLEGAL = RetCodes.retResult(RetCodes.RET_USER_AUTH_ILLEGAL);
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
//获取当前用户信息
|
||||
@Override
|
||||
protected UserInfo currentUser(HttpRequest req) throws IOException {
|
||||
String sessionid = req.getSessionid(false);
|
||||
if (sessionid == null || sessionid.isEmpty()) return null;
|
||||
return userService.current(sessionid);
|
||||
}
|
||||
|
||||
//普通鉴权
|
||||
@Override
|
||||
public boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException {
|
||||
UserInfo info = currentUser(request);
|
||||
if (info == null) {
|
||||
response.finishJson(RET_UNLOGIN);
|
||||
return false;
|
||||
} else if (!info.checkAuth(module, actionid)) {
|
||||
response.finishJson(RET_AUTHILLEGAL);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
42
test/org/redkale/test/rest/UserInfo.java
Normal file
42
test/org/redkale/test/rest/UserInfo.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package org.redkale.test.rest;
|
||||
|
||||
import org.redkale.convert.json.JsonFactory;
|
||||
|
||||
/**
|
||||
* 当前用户对象
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class UserInfo {
|
||||
|
||||
private int userid;
|
||||
|
||||
private String username = "";
|
||||
|
||||
public int getUserid() {
|
||||
return userid;
|
||||
}
|
||||
|
||||
public boolean checkAuth(int moduleid, int actionid) {
|
||||
if (moduleid == 0 || actionid == 0) return true;
|
||||
//权限判断
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setUserid(int userid) {
|
||||
this.userid = userid;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonFactory.root().getConvert().convertTo(this);
|
||||
}
|
||||
}
|
||||
21
test/org/redkale/test/rest/UserService.java
Normal file
21
test/org/redkale/test/rest/UserService.java
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.test.rest;
|
||||
|
||||
import org.redkale.service.Service;
|
||||
|
||||
/**
|
||||
* 简单的定义UserService接口
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class UserService implements Service {
|
||||
|
||||
//根据登录态获取当前用户信息
|
||||
public UserInfo current(String sessionid) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
119
test/org/redkale/test/rest/_DynHelloRestServlet1.java
Normal file
119
test/org/redkale/test/rest/_DynHelloRestServlet1.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package org.redkale.test.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import javax.annotation.Resource;
|
||||
import org.redkale.net.http.*;
|
||||
import org.redkale.service.RetResult;
|
||||
import org.redkale.source.Flipper;
|
||||
import org.redkale.util.*;
|
||||
import org.redkale.util.AnyValue.DefaultAnyValue;
|
||||
|
||||
@WebServlet(value = {"/hello/*"}, repair = true)
|
||||
public class _DynHelloRestServlet1 extends SimpleRestServlet {
|
||||
|
||||
@Resource
|
||||
private HelloService _service;
|
||||
|
||||
@Resource
|
||||
private Map<String, HelloService> _servicemap;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
final int port = 8888;
|
||||
HelloService service = new HelloService();
|
||||
HttpServer server = new HttpServer();
|
||||
|
||||
System.out.println(server.addRestServlet("", HelloService.class, service, SimpleRestServlet.class, "/pipes"));
|
||||
System.out.println(server.addRestServlet("my-res", HelloService.class, new HelloService(3), SimpleRestServlet.class, "/pipes"));
|
||||
|
||||
DefaultAnyValue conf = DefaultAnyValue.create("port", "" + port);
|
||||
server.init(conf);
|
||||
server.start();
|
||||
Thread.sleep(100);
|
||||
|
||||
HelloEntity entity = new HelloEntity();
|
||||
entity.setHelloname("my name");
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("hello-res", "my res");
|
||||
//headers.put(Rest.REST_HEADER_RESOURCE_NAME, "my-res");
|
||||
String url = "http://127.0.0.1:" + port + "/pipes/hello/update?entity={}&bean2={}";
|
||||
System.out.println(Utility.postHttpContent(url, headers, null));
|
||||
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/create")
|
||||
public void create(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||
UserInfo user = currentUser(req);
|
||||
RetResult<HelloEntity> result = service.createHello(user, bean);
|
||||
resp.finishJson(result);
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/delete/")
|
||||
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||
service.deleteHello(id);
|
||||
resp.finishJson(RetResult.success());
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/update")
|
||||
public void update(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
String clientaddr = req.getRemoteAddr();
|
||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||
service.updateHello(clientaddr, bean);
|
||||
resp.finishJson(RetResult.success());
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/partupdate")
|
||||
public void partupdate(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||
String[] cols = req.getJsonParameter(String[].class, "cols");
|
||||
service.updateHello(bean, cols);
|
||||
resp.finishJson(RetResult.success());
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/query")
|
||||
public void query(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
||||
Flipper flipper = req.getFlipper();
|
||||
Sheet<HelloEntity> result = service.queryHello(bean, flipper);
|
||||
resp.finishJson(result);
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/list")
|
||||
public void list(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
||||
List<HelloEntity> result = service.queryHello(bean);
|
||||
resp.finishJson(result);
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/find/")
|
||||
public void find(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||
HelloEntity bean = service.findHello(id);
|
||||
resp.finishJson(bean);
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/jsfind/")
|
||||
public void jsfind(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||
HelloEntity bean = service.findHello(id);
|
||||
resp.finishJsResult("varhello", bean);
|
||||
}
|
||||
}
|
||||
75
test/org/redkale/test/rest/_DynHelloRestServlet2.java
Normal file
75
test/org/redkale/test/rest/_DynHelloRestServlet2.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.test.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Resource;
|
||||
import org.redkale.net.http.*;
|
||||
import org.redkale.service.RetResult;
|
||||
import org.redkale.source.Flipper;
|
||||
import org.redkale.util.Sheet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@WebServlet(value = {"/hello/*"}, repair = true)
|
||||
public class _DynHelloRestServlet2 extends SimpleRestServlet {
|
||||
|
||||
@Resource
|
||||
private HelloService2 _service;
|
||||
|
||||
@Resource
|
||||
private Map<String, HelloService2> _servicemap;
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/create")
|
||||
public void create(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||
UserInfo user = currentUser(req);
|
||||
RetResult<HelloEntity> result = service.createHello(user, bean);
|
||||
resp.finishJson(result);
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/delete/")
|
||||
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||
service.deleteHello(id);
|
||||
resp.finishJson(RetResult.success());
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/update")
|
||||
public void update(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
|
||||
service.updateHello(bean);
|
||||
resp.finishJson(RetResult.success());
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/query")
|
||||
public void query(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
|
||||
Flipper flipper = req.getFlipper();
|
||||
Sheet<HelloEntity> result = service.queryHello(bean, flipper);
|
||||
resp.finishJson(result);
|
||||
}
|
||||
|
||||
@AuthIgnore
|
||||
@WebAction(url = "/hello/find/")
|
||||
public void find(HttpRequest req, HttpResponse resp) throws IOException {
|
||||
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
|
||||
int id = Integer.parseInt(req.getRequstURILastPath());
|
||||
HelloEntity bean = service.findHello(id);
|
||||
resp.finishJson(bean);
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public class SncpTest {
|
||||
set.add(addr);
|
||||
if (port2 > 0) set.add(new InetSocketAddress(myhost, port2));
|
||||
//String name, WatchFactory, ObjectPool<ByteBuffer>, AsynchronousChannelGroup, InetSocketAddress clientAddress, Collection<InetSocketAddress>
|
||||
final Transport transport = new Transport("", WatchFactory.root(), newBufferPool(), newChannelGroup(), null, set);
|
||||
final Transport transport = new Transport("", WatchFactory.root(), "", newBufferPool(), newChannelGroup(), null, set);
|
||||
final SncpTestService service = Sncp.createRemoteService(serviceName, null, SncpTestService.class, null, transport);
|
||||
ResourceFactory.root().inject(service);
|
||||
|
||||
@@ -97,7 +97,7 @@ public class SncpTest {
|
||||
callbean.setContent("数据X");
|
||||
|
||||
service.insert(callbean);
|
||||
System.out.println("bean.id应该会被修改: " + callbean);
|
||||
System.out.println("bean.id应该会被修改(id不会是1): " + callbean);
|
||||
System.out.println("---------------------------------------------------");
|
||||
final int count = 10;
|
||||
final CountDownLatch cld = new CountDownLatch(count);
|
||||
@@ -151,10 +151,10 @@ public class SncpTest {
|
||||
Set<InetSocketAddress> set = new LinkedHashSet<>();
|
||||
if (port2 > 0) set.add(new InetSocketAddress(myhost, port2));
|
||||
//String name, WatchFactory, ObjectPool<ByteBuffer>, AsynchronousChannelGroup, InetSocketAddress clientAddress, Collection<InetSocketAddress>
|
||||
final Transport transport = new Transport("", WatchFactory.root(), newBufferPool(), newChannelGroup(), null, set);
|
||||
final Transport transport = new Transport("", WatchFactory.root(), "", newBufferPool(), newChannelGroup(), null, set);
|
||||
SncpTestService service = Sncp.createLocalService("", null, ResourceFactory.root(), SncpTestService.class, addr, transport, null);
|
||||
ResourceFactory.root().inject(service);
|
||||
server.addService(new ServiceWrapper(service, "", "", new HashSet<>(), null));
|
||||
server.addSncpServlet(new ServiceWrapper(service, "", "", new HashSet<>(), null));
|
||||
System.out.println(service);
|
||||
AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue();
|
||||
conf.addValue("host", "0.0.0.0");
|
||||
@@ -185,9 +185,9 @@ public class SncpTest {
|
||||
Set<InetSocketAddress> set = new LinkedHashSet<>();
|
||||
set.add(new InetSocketAddress(myhost, port));
|
||||
//String name, WatchFactory, ObjectPool<ByteBuffer>, AsynchronousChannelGroup, InetSocketAddress clientAddress, Collection<InetSocketAddress>
|
||||
final Transport transport = new Transport("", WatchFactory.root(), newBufferPool(), newChannelGroup(), null, set);
|
||||
final Transport transport = new Transport("", WatchFactory.root(), "", newBufferPool(), newChannelGroup(), null, set);
|
||||
Service service = Sncp.createLocalService("", null, ResourceFactory.root(), SncpTestService.class, addr, transport, null);
|
||||
server.addService(new ServiceWrapper(service, "", "", new HashSet<>(), null));
|
||||
server.addSncpServlet(new ServiceWrapper(service, "", "", new HashSet<>(), null));
|
||||
AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue();
|
||||
conf.addValue("host", "0.0.0.0");
|
||||
conf.addValue("port", "" + port2);
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.redkale.convert.json.*;
|
||||
public class SncpTestBean implements FilterBean {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private long id;
|
||||
|
||||
private String content;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class UntilTestMain {
|
||||
Reproduce<TestXBean, TestBean> action2 = new Reproduce<TestXBean, TestBean>() {
|
||||
|
||||
@Override
|
||||
public TestXBean copy(TestXBean dest, TestBean src) {
|
||||
public TestXBean apply(TestXBean dest, TestBean src) {
|
||||
dest.time = src.time;
|
||||
dest.setId(src.getId());
|
||||
dest.setName(src.getName());
|
||||
@@ -40,13 +40,13 @@ public class UntilTestMain {
|
||||
final int count = 1_000_000;
|
||||
long s = System.nanoTime();
|
||||
for (int i = 0; i < count; i++) {
|
||||
action2.copy(beanx, bean);
|
||||
action2.apply(beanx, bean);
|
||||
}
|
||||
long e = System.nanoTime() - s;
|
||||
System.out.println("静态Reproduce耗时: " + e);
|
||||
s = System.nanoTime();
|
||||
for (int i = 0; i < count; i++) {
|
||||
action1.copy(beanx, bean);
|
||||
action1.apply(beanx, bean);
|
||||
}
|
||||
e = System.nanoTime() - s;
|
||||
System.out.println("动态Reproduce耗时: " + e);
|
||||
|
||||
@@ -9,12 +9,8 @@ import org.redkale.net.http.WebServlet;
|
||||
import org.redkale.net.http.WebSocketServlet;
|
||||
import org.redkale.net.http.WebSocket;
|
||||
import java.io.*;
|
||||
import static java.lang.Thread.sleep;
|
||||
import java.text.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import static java.lang.Thread.sleep;
|
||||
import static java.lang.Thread.sleep;
|
||||
import static java.lang.Thread.sleep;
|
||||
import org.redkale.util.Utility;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,8 +29,6 @@ public class ChatWebSocketServlet extends WebSocketServlet {
|
||||
debug = "true".equalsIgnoreCase(System.getProperty("debug", "false"));
|
||||
Thread t = new Thread() {
|
||||
|
||||
private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
{
|
||||
setName("Debug-ChatWebSocket-ShowCount-Thread");
|
||||
}
|
||||
@@ -47,7 +41,7 @@ public class ChatWebSocketServlet extends WebSocketServlet {
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
System.out.println(format.format(new java.util.Date()) + ": 消息总数: " + counter.get() + ",间隔消息数: " + icounter.getAndSet(0));
|
||||
System.out.println(Utility.now() + ": 消息总数: " + counter.get() + ",间隔消息数: " + icounter.getAndSet(0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,19 +113,15 @@ public class VideoWebSocketServlet extends WebSocketServlet {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
AnyValue.DefaultAnyValue config = new AnyValue.DefaultAnyValue();
|
||||
config.addValue("threads", System.getProperty("threads"));
|
||||
config.addValue("bufferPoolSize", System.getProperty("bufferPoolSize"));
|
||||
config.addValue("responsePoolSize", System.getProperty("responsePoolSize"));
|
||||
config.addValue("host", System.getProperty("host", "0.0.0.0"));
|
||||
config.addValue("port", System.getProperty("port", "8070"));
|
||||
config.addValue("root", System.getProperty("root", "./root3/"));
|
||||
AnyValue.DefaultAnyValue resConf = new AnyValue.DefaultAnyValue();
|
||||
resConf.setValue("cacheMaxLength", "200M");
|
||||
resConf.setValue("cacheMaxItemLength", "10M");
|
||||
config.setValue("ResourceServlet", resConf);
|
||||
AnyValue.DefaultAnyValue config = AnyValue.create()
|
||||
.addValue("threads", System.getProperty("threads"))
|
||||
.addValue("bufferPoolSize", System.getProperty("bufferPoolSize"))
|
||||
.addValue("responsePoolSize", System.getProperty("responsePoolSize"))
|
||||
.addValue("host", System.getProperty("host", "0.0.0.0"))
|
||||
.addValue("port", System.getProperty("port", "8070"))
|
||||
.addValue("root", System.getProperty("root", "./root3/"));
|
||||
HttpServer server = new HttpServer();
|
||||
server.addHttpServlet(new VideoWebSocketServlet(), "/pipes", null, "/listen/*");
|
||||
server.addHttpServlet("/pipes", new VideoWebSocketServlet(), "/listen/*");
|
||||
server.init(config);
|
||||
server.start();
|
||||
cdl.await();
|
||||
|
||||
Reference in New Issue
Block a user