This commit is contained in:
redkale
2024-05-27 13:02:25 +08:00
parent cbb224046c
commit 27bfda94a0
651 changed files with 137951 additions and 137951 deletions

View File

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

View File

@@ -13,11 +13,11 @@ redkale.cluster.waits= = false
redkale.cluster.protocols = SNCP redkale.cluster.protocols = SNCP
redkale.cluster.ports = 7070;7071 redkale.cluster.ports = 7070;7071
redkale.mq[0].name = redkale.mq[0].name =
redkale.mq[0].type = org.redkalex.mq.kafka.KafkaMessageAgent redkale.mq[0].type = org.redkalex.mq.kafka.KafkaMessageAgent
redkale.mq[0].servers.value = 127.0.0.1:9101 redkale.mq[0].servers.value = 127.0.0.1:9101
redkale.group[0].name = redkale.group[0].name =
redkale.group[0].protocol = TCP redkale.group[0].protocol = TCP
redkale.group[0].node[0].addr = 127.0.0.1 redkale.group[0].node[0].addr = 127.0.0.1
redkale.group[0].node[0].port = 7070 redkale.group[0].node[0].port = 7070
@@ -35,9 +35,9 @@ redkale.server[0].protocol = HTTP
redkale.server[0].host = 127.0.0.1 redkale.server[0].host = 127.0.0.1
redkale.server[0].port = 6060 redkale.server[0].port = 6060
redkale.server[0].root = root redkale.server[0].root = root
redkale.server[0].lib = redkale.server[0].lib =
#\u3010ssl\u8282\u70b9\u5728<server>\u4e2d\u552f\u4e00\u3011 #\u3010ssl\u8282\u70b9\u5728<server>\u4e2d\u552f\u4e00\u3011
redkale.server[0].ssl.build = org.redkale.net.SSLBuilder\u5b50\u7c7b redkale.server[0].ssl.build = org.redkale.net.SSLBuilder\u5b50\u7c7b
redkale.server[0].services[0].autoload = true redkale.server[0].services[0].autoload = true

View File

@@ -1,366 +1,366 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
文件说明: 文件说明:
${APP_HOME} 指当前程序的根目录APP_HOME ${APP_HOME} 指当前程序的根目录APP_HOME
没注明唯一的节点可多个存在 没注明唯一的节点可多个存在
required 被声明required的属性值不能为空 required 被声明required的属性值不能为空
group group
/ / \ \ / / \ \
/ / \ \ / / \ \
/ / \ \ / / \ \
node1 node2 node3 node4 node1 node2 node3 node4
/ \ / \
/ \ / \
/ \ / \
/ \ / \
serviceid1 serviceid2 serviceid1 serviceid2
/ \ / \ / \ / \
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2 serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
--> -->
<!-- <!--
nodeid: int 进程的节点ID用于分布式环境一个系统中节点ID必须全局唯一使用cluster时框架会进行唯一性校验 nodeid: int 进程的节点ID用于分布式环境一个系统中节点ID必须全局唯一使用cluster时框架会进行唯一性校验
name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线、短横、点 name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线、短横、点
address: 本地局域网的IP地址 默认值为默认网卡的ip当不使用默认值需要指定值如192.168.1.22 address: 本地局域网的IP地址 默认值为默认网卡的ip当不使用默认值需要指定值如192.168.1.22
port: required 程序的管理Server的端口用于关闭或者与监管系统进行数据交互 port: required 程序的管理Server的端口用于关闭或者与监管系统进行数据交互
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar; lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
--> -->
<application nodeid="1000" port="6560" lib=""> <application nodeid="1000" port="6560" lib="">
<!--
【节点全局唯一】 @since 2.3.0
全局Serivce执行的线程池 Application.workExecutor, 没配置该节点将自动创建一个。
threads 线程数,默认值: CPU核数*10, 核数=2的情况下默认值为20。值为0表示不启用workExecutor都在IO线程中运行。
clients client回调函数运行的线程池大小 默认值: CPU核数*4
-->
<executor threads="4"/>
<!-- <!--
【节点全局唯一】 @since 2.8.0 【节点全局唯一】 @since 2.3.0
全局Serivce的定时任务设置,没配置该节点将自动创建一个。 全局Serivce执行的线程池, Application.workExecutor, 没配置该节点将自动创建一个。
enabled 是否开启缓存功能。默认: true threads 线程数,默认: CPU核数*10, 核数=2的情况下默认值为20。值为0表示不启用workExecutor都在IO线程中运行。
--> clients client回调函数运行的线程池大小 默认值: CPU核数*4
<schedule enabled="true"/> -->
<executor threads="4"/>
<!--
【节点全局唯一】 @since 2.8.0
全局Serivce的缓存设置没配置该节点将自动创建一个。
enabled 是否开启缓存功能。默认: true
source: 远程CacheSource的资源名
-->
<cache enabled="true" source="xxx"/>
<!--
【节点全局唯一】
第三方服务发现管理接口
type 类名必须是org.redkale.cluster.ClusterAgent的子类
waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁默认值为false
当一个Service进行服务注销后不能立刻销毁Service因为健康检测是有间隔时间差的
需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
如果使用MQ可以设置为false如果对服务健壮性要求高建议设置为true
protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
ports: 服务发现可以处理的端口, 多个端口用分号;隔开
ttls: 心跳频率,多少秒一次
xxxx: 自定义的字段属性例如CacheClusterAgent有source字段; ConsulClusterAgent有apiurl字段;
-->
<cluster type="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071" xxx="xxx" />
<!-- <!--
MQ管理接口配置 【节点全局唯一】 @since 2.8.0
不同MQ节点所配置的MQ集群不能重复 全局Serivce的定时任务设置没配置该节点将自动创建一个
MQ跟着协议走所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的故SNCP协议下mq属性值被赋值在service/services节点上 enabled 是否开启缓存功能。默认: true
name: 服务的名称用于监控识别多个mq节点时只能有一个name为空的节点mq.name不能重复,命名规则: 字母、数字、下划线 -->
type 实现类名必须是org.redkale.mq.MessageAgent的子类 <schedule enabled="true"/>
threads线程数为0表示使用workExecutor。默认: CPU核数, 核数=1的情况下默认值为2JDK 21以上版本默认使用虚拟线程池
rpcfirstcluster和mq同名组件时HttpRpcClient优先使用MQ默认不优先走MQ。
coder: MessageRecord的解析器类必须是org.redkale.mq.MessageCoder<MessageRecord>的实现类,
可对数据包进行加密解密默认值org.redkale.mq.MessageRecordCoder
MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
-->
<mq name="" type="org.redkalex.mq.kafka.KafkaMessageAgent" rpcfirst="false" threads="4">
<servers value="127.0.0.1:9101"/>
<!--
加载所有的MessageConsumer实例;
autoload="true" 默认值. 自动加载classpath下所有的MessageConsumer类
autoload="false" 需要显著的指定MessageConsumer类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<consumer autoload="true" includes="" excludes=""/>
<!--
MQ实现方的配置项
type: 配置项类型值只能是consumer或producer
-->
<config type="consumer">
<property name="xxxxxx" value="XXXXXXXX"/>
</config>
<config type="producer">
<property name="xxxxxx" value="XXXXXXXX"/>
</config>
</mq>
<!--
一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol 值范围UDP TCP 默认TCP
nodes: 多个node节点值 例如:192.168.0.1:6060,192.168.0.2:6060
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
-->
<group name="" protocol="TCP" nodes="192.168.0.1:6060,192.168.0.2:6060">
<!--
需要将本地node的addr与port列在此处, 也可以直接用nodes属性。
同一个<node>节点值只能存在一个<group>节点内即同一个addr+port只能属于一个group。
addr: required IP地址
port: required 端口
-->
<node addr="127.0.0.1" port="7070"/>
</group>
<!-- <!--
Application启动的监听事件,可配置多个节点 【节点全局唯一】 @since 2.8.0
value: 类名必须是ApplicationListener的子类 全局Serivce的缓存设置没配置该节点将自动创建一个。
--> enabled 是否开启缓存功能。默认: true
<listener value="org.redkalex.xxx.XXXApplicationListener"/> source: 远程CacheSource的资源名
-->
<!-- <cache enabled="true" source="xxx"/>
【节点全局唯一】
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class <!--
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。 【节点全局唯一】
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。 第三方服务发现管理接口
先加载子节点property再加载load文件 最后加载agent的实现子类 type 类名必须是org.redkale.cluster.ClusterAgent的子类
load: 加载文件,多个用;隔开。 waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁默认值为false
其他属性: 供org.redkale.boot.PropertiesAgentProvider使用判断 当一个Service进行服务注销后不能立刻销毁Service因为健康检测是有间隔时间差的
默认置入的system.property.的有: 需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
System.setProperty("redkale.convert.pool.size", "128"); 如果使用MQ可以设置为false如果对服务健壮性要求高建议设置为true
System.setProperty("redkale.convert.writer.buffer.defsize", "4096"); protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
ports: 服务发现可以处理的端口, 多个端口用分号;隔开
<properties>节点下也可包含非<property>节点. ttls: 心跳频率,多少秒一次
非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[] xxxx: 自定义的字段属性例如CacheClusterAgent有source字段; ConsulClusterAgent有apiurl字段;
--> -->
<properties load="config.properties"> <cluster type="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071" xxx="xxx" />
<property name="system.property.yyyy" value="YYYYYY"/>
<property name="xxxxxx" value="XXXXXXXX"/> <!--
<property name="xxxxxx" value="XXXXXXXX"/> MQ管理接口配置
<property name="xxxxxx" value="XXXXXXXX"/> 不同MQ节点所配置的MQ集群不能重复。
</properties> MQ跟着协议走所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的故SNCP协议下mq属性值被赋值在service/services节点上
name: 服务的名称用于监控识别多个mq节点时只能有一个name为空的节点mq.name不能重复,命名规则: 字母、数字、下划线
<!-- type 实现类名必须是org.redkale.mq.MessageAgent的子类
protocol: required server所启动的协议Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。 threads线程数为0表示使用workExecutor。默认: CPU核数, 核数=1的情况下默认值为2JDK 21以上版本默认使用虚拟线程池
name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线 rpcfirstcluster和mq同名组件时HttpRpcClient优先使用MQ默认不优先走MQ。
host: 服务所占address 默认: 0.0.0.0 coder: MessageRecord的解析器类必须是org.redkale.mq.MessageCoder<MessageRecord>的实现类,
port: required 服务所占端口 可对数据包进行加密解密默认值org.redkale.mq.MessageRecordCoder
root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
lib: server额外的class目录 默认为${APP_HOME}/libs/*; -->
charset: 文本编码, 默认: UTF-8 <mq name="" type="org.redkalex.mq.kafka.KafkaMessageAgent" rpcfirst="false" threads="4">
backlog: 默认10K <servers value="127.0.0.1:9101"/>
maxconns 最大连接数, 小于1表示无限制 默认: 0 <!--
maxbody: request.body最大值 默认: 256K 加载所有的MessageConsumer实例;
bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 8K autoload="true" 默认值. 自动加载classpath下所有的MessageConsumer类
bufferPoolSize ByteBuffer池的大小默认: 线程数*4 autoload="false" 需要显著的指定MessageConsumer类
responsePoolSize Response池的大小默认: 1024 includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
readTimeoutSeconds: 读操作超时秒数, 默认0 0表示永久不超时 -->
writeTimeoutSeconds: 写操作超时秒数, 默认0 0表示永久不超时 <consumer autoload="true" includes="" excludes=""/>
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null <!--
--> MQ实现方的配置项
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib=""> type: 配置项类型值只能是consumer或producer
-->
<!-- <config type="consumer">
【节点在<server>中唯一】 <property name="xxxxxx" value="XXXXXXXX"/>
builder: 创建SSLContext的实现类, 可自定义必须是org.redkale.net.SSLBuilder的子类 </config>
sslProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.OpenSSLProvider、org.bouncycastle.jce.provider.BouncyCastleProvider <config type="producer">
jsseProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.JSSEProvider、 org.bouncycastle.jce.provider.BouncyCastleJsseProvider <property name="xxxxxx" value="XXXXXXXX"/>
protocol: TLS版本默认值: TLS </config>
protocols: 设置setEnabledProtocols, 多个用,隔开 如: TLSv1.2,TLSv1.3 </mq>
clientAuth: WANT/NEED/NONE, 默认值: NONE
ciphers: 设置setEnabledCipherSuites, 多个用,隔开 如: TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256 <!--
keystorePass: KEY密码 一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
keystoreFile: KEY文件 .jks name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
keystoreType: KEY类型 默认值为JKS protocol 值范围UDP TCP 默认TCP
keystoreAlgorithm: KEY文件的algorithm 默认值为SunX509 nodes: 多个node节点值 例如:192.168.0.1:6060,192.168.0.2:6060
truststorePass: TRUST密码 注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
truststoreFile: TRUST文件 -->
truststoreType: TRUST类型 默认值为JKS <group name="" protocol="TCP" nodes="192.168.0.1:6060,192.168.0.2:6060">
truststoreAlgorithm: TRUST文件的algorithm 默认值为SunX509 <!--
--> 需要将本地node的addr与port列在此处, 也可以直接用nodes属性。
<ssl builder=""/> 同一个<node>节点值只能存在一个<group>节点内即同一个addr+port只能属于一个group。
addr: required IP地址
<!-- port: required 端口
加载所有的Service服务; -->
在同一个进程中同一个name同一类型的Service将共用同一个实例 <node addr="127.0.0.1" port="7070"/>
autoload="true" 默认值. 自动加载classpath下所有的Service类 </group>
autoload="false" 需要显著的指定Service类
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式 <!--
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 Application启动的监听事件,可配置多个节点
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 value: 类名必须是ApplicationListener的子类
group: 所属组的节点, 不能指定多个group, 如果配置文件中存在多个SNCP协议的Server节点需要显式指定group属性. -->
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。 <listener value="org.redkalex.xxx.XXXApplicationListener"/>
当 protocol != SNCP 时 group只能是空或者一个group的节点值。
特殊值"$remote", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息 <!--
--> 【节点全局唯一】
<services autoload="true" includes="" excludes=""> 全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
先加载子节点property再加载load文件 最后加载agent的实现子类。
load: 加载文件,多个用;隔开。
其他属性: 供org.redkale.boot.PropertiesAgentProvider使用判断
默认置入的system.property.的有:
System.setProperty("redkale.convert.pool.size", "128");
System.setProperty("redkale.convert.writer.buffer.defsize", "4096");
<properties>节点下也可包含非<property>节点.
非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
-->
<properties load="config.properties">
<property name="system.property.yyyy" value="YYYYYY"/>
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</properties>
<!--
protocol: required server所启动的协议Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
host: 服务所占address 默认: 0.0.0.0
port: required 服务所占端口
root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root
lib: server额外的class目录 默认为${APP_HOME}/libs/*;
charset: 文本编码, 默认: UTF-8
backlog: 默认10K
maxconns 最大连接数, 小于1表示无限制 默认: 0
maxbody: request.body最大值 默认: 256K
bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 8K
bufferPoolSize ByteBuffer池的大小默认: 线程数*4
responsePoolSize Response池的大小默认: 1024
aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive
readTimeoutSeconds: 读操作超时秒数, 默认0 0表示永久不超时
writeTimeoutSeconds: 写操作超时秒数, 默认0 0表示永久不超时
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null
-->
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
<!--
【节点在<server>中唯一】
builder: 创建SSLContext的实现类, 可自定义必须是org.redkale.net.SSLBuilder的子类
sslProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.OpenSSLProvider、org.bouncycastle.jce.provider.BouncyCastleProvider
jsseProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.JSSEProvider、 org.bouncycastle.jce.provider.BouncyCastleJsseProvider
protocol: TLS版本默认值: TLS
protocols: 设置setEnabledProtocols, 多个用,隔开 如: TLSv1.2,TLSv1.3
clientAuth: WANT/NEED/NONE, 默认值: NONE
ciphers: 设置setEnabledCipherSuites, 多个用,隔开 如: TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256
keystorePass: KEY密码
keystoreFile: KEY文件 .jks
keystoreType: KEY类型 默认值为JKS
keystoreAlgorithm: KEY文件的algorithm 默认值为SunX509
truststorePass: TRUST密码
truststoreFile: TRUST文件
truststoreType: TRUST类型 默认值为JKS
truststoreAlgorithm: TRUST文件的algorithm 默认值为SunX509
-->
<ssl builder=""/>
<!--
加载所有的Service服务;
在同一个进程中同一个name同一类型的Service将共用同一个实例
autoload="true" 默认值. 自动加载classpath下所有的Service类
autoload="false" 需要显著的指定Service类
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
group: 所属组的节点, 不能指定多个group, 如果配置文件中存在多个SNCP协议的Server节点需要显式指定group属性.
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
当 protocol != SNCP 时 group只能是空或者一个group的节点值。
特殊值"$remote", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息
-->
<services autoload="true" includes="" excludes="">
<!-- 显著加载指定的Service的接口类 -->
<service value="com.xxx.XXX1Service"/>
<!--
name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
group: 显式指定group覆盖<services>节点的group默认值。
ignore: 是否禁用, 默认为false。
-->
<service value="com.xxx.XXX2Service" name="" group="xxx"/>
<!-- 给Service增加配置属性 -->
<service value="com.xxx.XXX1Service">
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</service>
</services>
<!--
加载所有的Filter服务;
autoload="true" 默认值.
autoload="false" 需要显著的指定Filter类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<filters autoload="true" includes="" excludes="">
<!--
显著加载指定的Filter类
value=: Filter类名。必须与Server的协议层相同HTTP必须是HttpFilter
ignore: 是否禁用, 默认为false。
-->
<!-- 显著加载指定的Filter类 -->
<filter value="com.xxx.XXX1Filter"/>
<!-- 给Filter增加配置属性 -->
<filter value="com.xxx.XXX12Filter">
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</filter>
</filters>
<!--
REST的核心配置项
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置系统会自动生成)
path: servlet的ContextPath前缀 默认为空 【注: 开启MQ时,该字段失效】
base: REST服务的BaseServlet必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
mq: 所属的MQ管理器, 存在该属性表示RestService的请求来自于消息总线 【注: 开启MQ时,path字段失效】
autoload默认值"true" 默认值. 加载当前server所能使用的Servce对象;
includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<rest path="/pipes" base="org.redkale.net.http.HttpServlet" autoload="true" includes="" excludes="">
<!--
value: Service类名列出的表示必须被加载的Service对象
ignore: 是否忽略设置为true则不会加载该Service对象默认值为false
-->
<service value="com.xxx.XXXXService"/>
<!--
value: WebSocket类名列出的表示必须被加载且标记为@RestWebSocket的WebSocket对象
ignore: 是否忽略设置为true则不会加载该RestWebSocket对象默认值为false
-->
<websocket value="com.xxx.XXXXRestWebSocket"/>
</rest>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时, request节点才有效。
remoteaddr 节点: 替换请求方节点的IP地址 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。
且value值只能是以request.headers.开头表示从request.headers中获取对应的header值。
locale value值必须是request.headers.或request.parameters.开头。
例如下面例子获取request.getRemoteAddr()值如果header存在X-RemoteAddress值则返回X-RemoteAddress值不存在返回getRemoteAddress()。
-->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
<locale value="request.headers.locale" />
<rpc authenticator="org.redkale.net.http.HttpRpcAuthenticator的实现类"/>
</request>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时, response节点才有效。
contenttype: plain值为调用finish时的ContentType; 默认值: text/plain; charset=utf-8
json值为调用finishJson时的ContentType; 默认值: application/json; charset=utf-8
defcookie 节点: 当response里输出的cookie没有指定domain 和path时使用该节点的默认值。
addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader
options 节点: 设置了该节点且auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
date 节点: 设置了该节点且period有值(单位:毫秒);返回response会包含Date头信息默认为period=0
period=0表示实时获取当前时间;
period<0表示不设置date;
period>0表示定时获取时间; 设置1000表示每秒刷新Date时间
-->
<response>
<content-type plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/>
<defcookie domain="" path=""/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" /> <!-- 可多节点 -->
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/> <!-- 可多节点 -->
<setheader name="Access-Control-Allow-Credentials" value="true"/>
<options auto="true" />
<date period="0" />
</response>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时render才有效. 指定输出引擎的实现类
value: 输出引擎的实现类, 必须是org.redkale.net.http.HttpRender的子类
suffixs: 引擎文件名后缀,多个用;隔开,默认值为: .htel
-->
<render value="org.redkalex.htel.HttpTemplateRender" suffixs=".htel"/>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
webroot: web资源的根目录, 默认取server节点中的root值
servlet: 静态资源HttpServlet的实现默认使用HttpResourceServlet
index : 启始页默认值index.html
-->
<resource-servlet webroot="root" index="index.html">
<!--
【节点在<resource-servlet>中唯一】
资源缓存的配置, 默认存在一个含默认属性的caches节点
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存 单位可以是B、K、M、G不区分大小写
lengthmax: 可缓存的文件大小上限, 默认: 1M超过1M的文件不会被缓存
watch: 是否监控缓存文件的变化, 默认为false不监控
-->
<cache limit="0M" lengthmax="1M" watch="false"/>
<!--
支持类似nginx中的rewrite 目前只支持静态资源对静态资源的跳转。
type: 匹配的类型, 目前只支持location(匹配path), 默认: location
match: 匹配的正则表达式
forward: 需跳转后的资源链接
例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html
-->
<rewrite type="location" match="^/([^-]+)-[^-\.]+\.html(.*)" forward="/$1.html"/>
</resource-servlet>
<!--
加载所有的Servlet服务;
path: servlet的ContextPath前缀 默认为空
autoload="true" 默认值. 自动加载classpath下所有的Servlet类
autoload="false" 需要显著的指定Service类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<servlets path="/pipes" autoload="true" includes="" excludes="">
<!--
显著加载指定的Servlet类
value=: Servlet类名。必须与Server的协议层相同HTTP必须是HttpServlet
ignore: 是否禁用, 默认为false。
-->
<servlet value="com.xxx.XXX1Servlet" />
<servlet value="com.xxx.XXX2Servlet" />
<servlet value="com.xxx.XXX3Servlet" >
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="yyyyyy" value="YYYYYYYY"/>
</servlet>
</servlets>
</server>
<server protocol="SNCP" host="127.0.0.1" port="7070" root="root" lib="">
<!-- 参数完全同上 -->
<services autoload="true" includes="" excludes="" />
</server>
<!-- 显著加载指定的Service的接口类 -->
<service value="com.xxx.XXX1Service"/>
<!--
name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
group: 显式指定group覆盖<services>节点的group默认值。
ignore: 是否禁用, 默认为false。
-->
<service value="com.xxx.XXX2Service" name="" group="xxx"/>
<!-- 给Service增加配置属性 -->
<service value="com.xxx.XXX1Service">
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</service>
</services>
<!--
加载所有的Filter服务;
autoload="true" 默认值.
autoload="false" 需要显著的指定Filter类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<filters autoload="true" includes="" excludes="">
<!--
显著加载指定的Filter类
value=: Filter类名。必须与Server的协议层相同HTTP必须是HttpFilter
ignore: 是否禁用, 默认为false。
-->
<!-- 显著加载指定的Filter类 -->
<filter value="com.xxx.XXX1Filter"/>
<!-- 给Filter增加配置属性 -->
<filter value="com.xxx.XXX12Filter">
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</filter>
</filters>
<!--
REST的核心配置项
当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置系统会自动生成)
path: servlet的ContextPath前缀 默认为空 【注: 开启MQ时,该字段失效】
base: REST服务的BaseServlet必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。
mq: 所属的MQ管理器, 存在该属性表示RestService的请求来自于消息总线 【注: 开启MQ时,path字段失效】
autoload默认值"true" 默认值. 加载当前server所能使用的Servce对象;
includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<rest path="/pipes" base="org.redkale.net.http.HttpServlet" autoload="true" includes="" excludes="">
<!--
value: Service类名列出的表示必须被加载的Service对象
ignore: 是否忽略设置为true则不会加载该Service对象默认值为false
-->
<service value="com.xxx.XXXXService"/>
<!--
value: WebSocket类名列出的表示必须被加载且标记为@RestWebSocket的WebSocket对象
ignore: 是否忽略设置为true则不会加载该RestWebSocket对象默认值为false
-->
<websocket value="com.xxx.XXXXRestWebSocket"/>
</rest>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时, request节点才有效。
remoteaddr 节点: 替换请求方节点的IP地址 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。
且value值只能是以request.headers.开头表示从request.headers中获取对应的header值。
locale value值必须是request.headers.或request.parameters.开头。
例如下面例子获取request.getRemoteAddr()值如果header存在X-RemoteAddress值则返回X-RemoteAddress值不存在返回getRemoteAddress()。
-->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
<locale value="request.headers.locale" />
<rpc authenticator="org.redkale.net.http.HttpRpcAuthenticator的实现类"/>
</request>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时, response节点才有效。
contenttype: plain值为调用finish时的ContentType; 默认值: text/plain; charset=utf-8
json值为调用finishJson时的ContentType; 默认值: application/json; charset=utf-8
defcookie 节点: 当response里输出的cookie没有指定domain 和path时使用该节点的默认值。
addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader
options 节点: 设置了该节点且auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
date 节点: 设置了该节点且period有值(单位:毫秒);返回response会包含Date头信息默认为period=0
period=0表示实时获取当前时间;
period<0表示不设置date;
period>0表示定时获取时间; 设置1000表示每秒刷新Date时间
-->
<response>
<content-type plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/>
<defcookie domain="" path=""/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" /> <!-- 可多节点 -->
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/> <!-- 可多节点 -->
<setheader name="Access-Control-Allow-Credentials" value="true"/>
<options auto="true" />
<date period="0" />
</response>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时render才有效. 指定输出引擎的实现类
value: 输出引擎的实现类, 必须是org.redkale.net.http.HttpRender的子类
suffixs: 引擎文件名后缀,多个用;隔开,默认值为: .htel
-->
<render value="org.redkalex.htel.HttpTemplateRender" suffixs=".htel"/>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点
webroot: web资源的根目录, 默认取server节点中的root值
servlet: 静态资源HttpServlet的实现默认使用HttpResourceServlet
index : 启始页默认值index.html
-->
<resource-servlet webroot="root" index="index.html">
<!--
【节点在<resource-servlet>中唯一】
资源缓存的配置, 默认存在一个含默认属性的caches节点
limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存 单位可以是B、K、M、G不区分大小写
lengthmax: 可缓存的文件大小上限, 默认: 1M超过1M的文件不会被缓存
watch: 是否监控缓存文件的变化, 默认为false不监控
-->
<cache limit="0M" lengthmax="1M" watch="false"/>
<!--
支持类似nginx中的rewrite 目前只支持静态资源对静态资源的跳转。
type: 匹配的类型, 目前只支持location(匹配path), 默认: location
match: 匹配的正则表达式
forward: 需跳转后的资源链接
例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html
-->
<rewrite type="location" match="^/([^-]+)-[^-\.]+\.html(.*)" forward="/$1.html"/>
</resource-servlet>
<!--
加载所有的Servlet服务;
path: servlet的ContextPath前缀 默认为空
autoload="true" 默认值. 自动加载classpath下所有的Servlet类
autoload="false" 需要显著的指定Service类
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
<servlets path="/pipes" autoload="true" includes="" excludes="">
<!--
显著加载指定的Servlet类
value=: Servlet类名。必须与Server的协议层相同HTTP必须是HttpServlet
ignore: 是否禁用, 默认为false。
-->
<servlet value="com.xxx.XXX1Servlet" />
<servlet value="com.xxx.XXX2Servlet" />
<servlet value="com.xxx.XXX3Servlet" >
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="yyyyyy" value="YYYYYYYY"/>
</servlet>
</servlets>
</server>
<server protocol="SNCP" host="127.0.0.1" port="7070" root="root" lib="">
<!-- 参数完全同上 -->
<services autoload="true" includes="" excludes="" />
</server>
</application> </application>

View File

@@ -19,7 +19,7 @@ java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%tY%tm/log-%tY%tm%td.lo
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d #java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log
#\u9700\u8981\u5c4f\u853d\u6d88\u606f\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f #\u9700\u8981\u5c4f\u853d\u6d88\u606f\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f
java.util.logging.FileHandler.denyregx = java.util.logging.FileHandler.denyregx =
java.util.logging.FileHandler.append = true java.util.logging.FileHandler.append = true
#java.util.logging.ConsoleHandler.level = FINE #java.util.logging.ConsoleHandler.level = FINE

View File

@@ -47,4 +47,4 @@ redkale.datasource.platf.read.password = 12345678
redkale.datasource.platf.write.url = jdbc:mysql://127.0.0.1:3306/platf_w?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8 redkale.datasource.platf.write.url = jdbc:mysql://127.0.0.1:3306/platf_w?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8
redkale.datasource.platf.write.user = root redkale.datasource.platf.write.user = root
redkale.datasource.platf.write.password = 12345678 redkale.datasource.platf.write.password = 12345678

View File

@@ -30,10 +30,10 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Priority { public @interface Priority {
/** /**
* 优先级值 * 优先级值
* *
* @return int * @return int
*/ */
int value(); int value();
} }

View File

@@ -17,67 +17,67 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Resource { public @interface Resource {
// /** // /**
// * AuthenticationType // * AuthenticationType
// */ // */
// @Deprecated // @Deprecated
// public enum AuthenticationType { // public enum AuthenticationType {
// /** // /**
// * @deprecated // * @deprecated
// */ // */
// CONTAINER, // CONTAINER,
// /** // /**
// * @deprecated // * @deprecated
// */ // */
// APPLICATION // APPLICATION
// } // }
// //
/** /**
* 资源名称 * 资源名称
* *
* @return String * @return String
*/ */
public String name() default ""; public String name() default "";
/** /**
* 依赖注入的类型 * 依赖注入的类型
* *
* @return Class * @return Class
*/ */
public Class<?> type() default Object.class; public Class<?> type() default Object.class;
// //
// /** // /**
// * // *
// * @return AuthenticationType // * @return AuthenticationType
// */ // */
// @Deprecated // @Deprecated
// public AuthenticationType authenticationType() default AuthenticationType.CONTAINER; // public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
// //
// /** // /**
// * // *
// * @return boolean // * @return boolean
// */ // */
// @Deprecated // @Deprecated
// public boolean shareable() default true; // public boolean shareable() default true;
// //
// /** // /**
// * // *
// * @return String // * @return String
// */ // */
// @Deprecated // @Deprecated
// public String description() default ""; // public String description() default "";
// //
// /** // /**
// * // *
// * @return String // * @return String
// */ // */
// @Deprecated // @Deprecated
// public String mappedName() default ""; // public String mappedName() default "";
// //
// /** // /**
// * // *
// * @return String // * @return String
// */ // */
// @Deprecated // @Deprecated
// public String lookup() default ""; // public String lookup() default "";
} }

View File

@@ -35,24 +35,24 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Cacheable { public @interface Cacheable {
/** /**
* (Optional) Whether or not the entity should be cached. * (Optional) Whether or not the entity should be cached.
* *
* @return boolean * @return boolean
*/ */
boolean value() default true; boolean value() default true;
/** /**
* (Optional) 定时自动更新缓存的周期秒数为0表示不做定时更新 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache * (Optional) 定时自动更新缓存的周期秒数为0表示不做定时更新 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
* *
* @return int * @return int
*/ */
int interval() default 0; int interval() default 0;
/** /**
* DataSource是否直接返回对象的真实引用 而不是copy一份 * DataSource是否直接返回对象的真实引用 而不是copy一份
* *
* @return boolean * @return boolean
*/ */
boolean direct() default false; boolean direct() default false;
} }

View File

@@ -56,92 +56,92 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Column { public @interface Column {
/** /**
* (Optional) The name of the column. Defaults to the property or field name. * (Optional) The name of the column. Defaults to the property or field name.
* *
* @return String * @return String
*/ */
String name() default ""; String name() default "";
/** /**
* (Optional) The comment of the column. * (Optional) The comment of the column.
* *
* @return String * @return String
*/ */
String comment() default ""; String comment() default "";
/** /**
* (Optional) Whether the column is a unique key. This is a shortcut for the <code>UniqueConstraint</code> * (Optional) Whether the column is a unique key. This is a shortcut for the <code>UniqueConstraint</code>
* annotation at the table level and is useful for when the unique key constraint corresponds to only a single * annotation at the table level and is useful for when the unique key constraint corresponds to only a single
* column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints * column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints
* specified at the table level. * specified at the table level.
* *
* @return boolean * @return boolean
*/ */
boolean unique() default false; boolean unique() default false;
/** /**
* (Optional) Whether the database column is required. * (Optional) Whether the database column is required.
* *
* @return boolean * @return boolean
*/ */
boolean nullable() default true; boolean nullable() default true;
/** /**
* for OpenAPI Specification 3 * for OpenAPI Specification 3
* *
* @return String * @return String
*/ */
String example() default ""; String example() default "";
/** /**
* (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider. * (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider.
* *
* @return boolean * @return boolean
*/ */
boolean insertable() default true; boolean insertable() default true;
/** /**
* (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider. * (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider.
* *
* @return boolean * @return boolean
*/ */
boolean updatable() default true; boolean updatable() default true;
/** /**
* (Optional) The name of the table that contains the column. If absent the column is assumed to be in the primary * (Optional) The name of the table that contains the column. If absent the column is assumed to be in the primary
* table. * table.
* *
* @return String * @return String
*/ */
@Deprecated @Deprecated
String table() default ""; String table() default "";
/** /**
* (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length == * (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length ==
* 65535 then sqltype is TEXT <br> * 65535 then sqltype is TEXT <br>
* if type==String and length &#60;= 16777215 then sqltype is MEDIUMTEXT <br> * if type==String and length &#60;= 16777215 then sqltype is MEDIUMTEXT <br>
* if type==String and length &#62; 16777215 then sqltype is LONGTEXT <br> * if type==String and length &#62; 16777215 then sqltype is LONGTEXT <br>
* if type==byte[] and length &#60;= 65535 then sqltype is BLOB <br> * if type==byte[] and length &#60;= 65535 then sqltype is BLOB <br>
* if type==byte[] and length &#60;= 16777215 then sqltype is MEDIUMBLOB <br> * if type==byte[] and length &#60;= 16777215 then sqltype is MEDIUMBLOB <br>
* if type==byte[] and length &#62; 16777215 then sqltype is LONGBLOB <br> * if type==byte[] and length &#62; 16777215 then sqltype is LONGBLOB <br>
* *
* @return int * @return int
*/ */
int length() default 255; int length() default 255;
/** /**
* (Optional) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.) Value * (Optional) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.) Value
* must be set by developer if used when generating the DDL for the column. * must be set by developer if used when generating the DDL for the column.
* *
* @return int * @return int
*/ */
int precision() default 0; int precision() default 0;
/** /**
* (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.) * (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.)
* *
* @return int * @return int
*/ */
int scale() default 0; int scale() default 0;
} }

View File

@@ -32,18 +32,18 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Entity { public @interface Entity {
/** /**
* (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to * (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to
* the entity in queries. The name must not be a reserved literal in the Java Persistence query language. * the entity in queries. The name must not be a reserved literal in the Java Persistence query language.
* *
* @return String * @return String
*/ */
String name() default ""; String name() default "";
/** /**
* (Optional) The comment of the entity. * (Optional) The comment of the entity.
* *
* @return String * @return String
*/ */
String comment() default ""; String comment() default "";
} }

View File

@@ -41,24 +41,24 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Index { public @interface Index {
/** /**
* (Optional) The name of the index; defaults to a provider-generated name. * (Optional) The name of the index; defaults to a provider-generated name.
* *
* @return String * @return String
*/ */
String name() default ""; String name() default "";
/** /**
* (Required) The names of the columns to be included in the index, in order. * (Required) The names of the columns to be included in the index, in order.
* *
* @return String * @return String
*/ */
String columnList(); String columnList();
/** /**
* (Optional) Whether the index is unique. * (Optional) Whether the index is unique.
* *
* @return boolean * @return boolean
*/ */
boolean unique() default false; boolean unique() default false;
} }

View File

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

View File

@@ -40,18 +40,18 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface UniqueConstraint { public @interface UniqueConstraint {
/** /**
* (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified. * (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified.
* *
* @return String * @return String
* @since Java Persistence 2.0 * @since Java Persistence 2.0
*/ */
String name() default ""; String name() default "";
/** /**
* (Required) An array of the column names that make up the constraint. * (Required) An array of the column names that make up the constraint.
* *
* @return String[] * @return String[]
*/ */
String[] columnNames(); String[] columnNames();
} }

View File

@@ -4,51 +4,51 @@
* @author zhangjx * @author zhangjx
*/ */
module org.redkale { module org.redkale {
requires java.base; requires java.base;
requires java.logging; requires java.logging;
requires java.net.http; requires java.net.http;
requires java.sql; requires java.sql;
requires jdk.unsupported; // sun.misc.Unsafe requires jdk.unsupported; // sun.misc.Unsafe
exports org.redkale.annotation; exports org.redkale.annotation;
exports org.redkale.boot; exports org.redkale.boot;
exports org.redkale.boot.watch; exports org.redkale.boot.watch;
exports org.redkale.cache; exports org.redkale.cache;
exports org.redkale.cache.spi; exports org.redkale.cache.spi;
exports org.redkale.cluster; exports org.redkale.cluster;
exports org.redkale.cluster.spi; exports org.redkale.cluster.spi;
exports org.redkale.convert; exports org.redkale.convert;
exports org.redkale.convert.bson; exports org.redkale.convert.bson;
exports org.redkale.convert.ext; exports org.redkale.convert.ext;
exports org.redkale.convert.json; exports org.redkale.convert.json;
exports org.redkale.convert.proto; exports org.redkale.convert.proto;
exports org.redkale.convert.spi; exports org.redkale.convert.spi;
exports org.redkale.inject; exports org.redkale.inject;
exports org.redkale.lock; exports org.redkale.lock;
exports org.redkale.lock.spi; exports org.redkale.lock.spi;
exports org.redkale.mq; exports org.redkale.mq;
exports org.redkale.mq.spi; exports org.redkale.mq.spi;
exports org.redkale.net; exports org.redkale.net;
exports org.redkale.net.client; exports org.redkale.net.client;
exports org.redkale.net.http; exports org.redkale.net.http;
exports org.redkale.net.sncp; exports org.redkale.net.sncp;
exports org.redkale.persistence; exports org.redkale.persistence;
exports org.redkale.props.spi; exports org.redkale.props.spi;
exports org.redkale.schedule; exports org.redkale.schedule;
exports org.redkale.schedule.spi; exports org.redkale.schedule.spi;
exports org.redkale.service; exports org.redkale.service;
exports org.redkale.source; exports org.redkale.source;
exports org.redkale.source.spi; exports org.redkale.source.spi;
exports org.redkale.util; exports org.redkale.util;
exports org.redkale.watch; exports org.redkale.watch;
uses org.redkale.props.spi.PropertiesAgentProvider; uses org.redkale.props.spi.PropertiesAgentProvider;
uses org.redkale.cache.spi.CacheManagerProvider; uses org.redkale.cache.spi.CacheManagerProvider;
uses org.redkale.cluster.spi.ClusterAgentProvider; uses org.redkale.cluster.spi.ClusterAgentProvider;
uses org.redkale.convert.spi.ConvertProvider; uses org.redkale.convert.spi.ConvertProvider;
uses org.redkale.mq.spi.MessageAgentProvider; uses org.redkale.mq.spi.MessageAgentProvider;
uses org.redkale.schedule.spi.ScheduleManagerProvider; uses org.redkale.schedule.spi.ScheduleManagerProvider;
uses org.redkale.source.spi.CacheSourceProvider; uses org.redkale.source.spi.CacheSourceProvider;
uses org.redkale.source.spi.DataSourceProvider; uses org.redkale.source.spi.DataSourceProvider;
uses org.redkale.source.spi.DataNativeSqlParserProvider; uses org.redkale.source.spi.DataNativeSqlParserProvider;
} }

View File

@@ -22,5 +22,5 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface AutoLoad { public @interface AutoLoad {
boolean value() default true; boolean value() default true;
} }

View File

@@ -21,5 +21,5 @@ import java.lang.annotation.*;
@Retention(SOURCE) @Retention(SOURCE)
public @interface ClassDepends { public @interface ClassDepends {
Class[] value() default {}; Class[] value() default {};
} }

View File

@@ -23,25 +23,25 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Command { public @interface Command {
/** /**
* 命令号,没有指定值则接收所有的命令 * 命令号,没有指定值则接收所有的命令
* *
* @return String * @return String
*/ */
String value() default ""; String value() default "";
/** /**
* 参数帮助说明在value不为空命令redkale --help时显示 * 参数帮助说明在value不为空命令redkale --help时显示
* *
* @return String * @return String
* @since 2.7.0 * @since 2.7.0
*/ */
String description() default ""; String description() default "";
/** /**
* 描述 * 描述
* *
* @return String * @return String
*/ */
String comment() default ""; String comment() default "";
} }

View File

@@ -23,7 +23,7 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Comment { public @interface Comment {
String name() default ""; String name() default "";
String value(); String value();
} }

View File

@@ -23,5 +23,5 @@ import java.lang.annotation.*;
@ClassDepends @ClassDepends
public @interface ConstructorParameters { public @interface ConstructorParameters {
String[] value(); String[] value();
} }

View File

@@ -37,15 +37,15 @@ import java.lang.annotation.*;
@Repeatable(LogExcludeLevel.LogExcludeLevels.class) @Repeatable(LogExcludeLevel.LogExcludeLevels.class)
public @interface LogExcludeLevel { public @interface LogExcludeLevel {
String[] levels(); String[] levels();
String[] keys(); String[] keys();
@Documented @Documented
@Target({TYPE}) @Target({TYPE})
@Retention(RUNTIME) @Retention(RUNTIME)
@interface LogExcludeLevels { @interface LogExcludeLevels {
LogExcludeLevel[] value(); LogExcludeLevel[] value();
} }
} }

View File

@@ -22,5 +22,5 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface LogLevel { public @interface LogLevel {
String value(); String value();
} }

View File

@@ -21,5 +21,5 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface NonBlocking { // 不可使用@Inherited防止被继承, 见HttpServlet.preExecute/authenticate/execute public @interface NonBlocking { // 不可使用@Inherited防止被继承, 见HttpServlet.preExecute/authenticate/execute
boolean value() default true; boolean value() default true;
} }

View File

@@ -23,7 +23,7 @@ import java.lang.annotation.Target;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Param { public @interface Param {
String value(); String value();
String comment() default ""; String comment() default "";
} }

View File

@@ -30,16 +30,16 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Priority { public @interface Priority {
/** 最高优先级, 其他值必须比此值小 */ /** 最高优先级, 其他值必须比此值小 */
public static final int HIGHTEST = Integer.MAX_VALUE; public static final int HIGHTEST = Integer.MAX_VALUE;
/** 最低优先级, 其他值必须比此值大 */ /** 最低优先级, 其他值必须比此值大 */
public static final int LOWEST = Integer.MIN_VALUE; public static final int LOWEST = Integer.MIN_VALUE;
/** /**
* 优先级值 * 优先级值
* *
* @return int * @return int
*/ */
int value(); int value();
} }

View File

@@ -19,42 +19,42 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Resource { public @interface Resource {
public static final String PARENT_NAME = "@"; public static final String PARENT_NAME = "@";
public static final String SELF_NAME = "#name"; public static final String SELF_NAME = "#name";
public static final String SELF_TYPE = "#type"; public static final String SELF_TYPE = "#type";
/** /**
* 是否必须存在 * 是否必须存在
* *
* @return boolean * @return boolean
* @since 2.8.0 * @since 2.8.0
*/ */
public boolean required() default true; public boolean required() default true;
/** /**
* 资源名称 <br> * 资源名称 <br>
* *
* <blockquote> * <blockquote>
* *
* <pre> * <pre>
* name规则: * name规则:
* 1: "@"有特殊含义, 表示资源本身,"@"不能单独使用 * 1: "@"有特殊含义, 表示资源本身,"@"不能单独使用
* 2: "#name"、"#type"有特殊含义 * 2: "#name"、"#type"有特殊含义
* 3: 只能是字母、数字、(短横)-、(下划线)_、点(.)的组合 * 3: 只能是字母、数字、(短横)-、(下划线)_、点(.)的组合
* </pre> * </pre>
* *
* </blockquote> * </blockquote>
* *
* @return String * @return String
*/ */
public String name() default ""; public String name() default "";
/** /**
* 依赖注入的类型 * 依赖注入的类型
* *
* @return Class * @return Class
*/ */
public Class<?> type() default Object.class; public Class<?> type() default Object.class;
} }

View File

@@ -55,12 +55,12 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ResourceChanged { public @interface ResourceChanged {
/** /**
* 新旧值是否不同时才回调方法 <br> * 新旧值是否不同时才回调方法 <br>
* true: 新值与旧值不同时才回调ResourceChanged方法 false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法 * true: 新值与旧值不同时才回调ResourceChanged方法 false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法
* *
* @since 2.7.0 * @since 2.7.0
* @return boolean * @return boolean
*/ */
boolean different() default true; boolean different() default true;
} }

View File

@@ -24,5 +24,5 @@ import java.lang.annotation.*;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ResourceType { public @interface ResourceType {
Class value(); Class value();
} }

View File

@@ -68,103 +68,103 @@ package org.redkale.asm;
*/ */
public abstract class AnnotationVisitor { public abstract class AnnotationVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
protected final int api; protected final int api;
/** The annotation visitor to which this visitor must delegate method calls. May be null. */ /** The annotation visitor to which this visitor must delegate method calls. May be null. */
protected AnnotationVisitor av; protected AnnotationVisitor av;
/** /**
* Constructs a new {@link AnnotationVisitor}. * Constructs a new {@link AnnotationVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
public AnnotationVisitor(final int api) { public AnnotationVisitor(final int api) {
this(api, null); this(api, null);
} }
/** /**
* Constructs a new {@link AnnotationVisitor}. * Constructs a new {@link AnnotationVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param av the annotation visitor to which this visitor must delegate method calls. May be null. * @param av the annotation visitor to which this visitor must delegate method calls. May be null.
*/ */
public AnnotationVisitor(final int api, final AnnotationVisitor av) { public AnnotationVisitor(final int api, final AnnotationVisitor av) {
this.api = api; this.api = api;
this.av = av; this.av = av;
} }
/** /**
* Visits a primitive value of the annotation. * Visits a primitive value of the annotation.
* *
* @param name the value name. * @param name the value name.
* @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character}, * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character},
* {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type} * {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type}
* of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or * of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or
* double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in * double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in
* turn, but is more convenient). * turn, but is more convenient).
*/ */
public void visit(String name, Object value) { public void visit(String name, Object value) {
if (av != null) { if (av != null) {
av.visit(name, value); av.visit(name, value);
} }
} }
/** /**
* Visits an enumeration value of the annotation. * Visits an enumeration value of the annotation.
* *
* @param name the value name. * @param name the value name.
* @param desc the class descriptor of the enumeration class. * @param desc the class descriptor of the enumeration class.
* @param value the actual enumeration value. * @param value the actual enumeration value.
*/ */
public void visitEnum(String name, String desc, String value) { public void visitEnum(String name, String desc, String value) {
if (av != null) { if (av != null) {
av.visitEnum(name, desc, value); av.visitEnum(name, desc, value);
} }
} }
/** /**
* Visits a nested annotation value of the annotation. * Visits a nested annotation value of the annotation.
* *
* @param name the value name. * @param name the value name.
* @param desc the class descriptor of the nested annotation class. * @param desc the class descriptor of the nested annotation class.
* @return a visitor to visit the actual nested annotation value, or &#60;tt&#62;null&#60;/tt&#62; if this visitor * @return a visitor to visit the actual nested annotation value, or &#60;tt&#62;null&#60;/tt&#62; if this visitor
* is not interested in visiting this nested annotation. <i>The nested annotation value must be fully visited * is not interested in visiting this nested annotation. <i>The nested annotation value must be fully visited
* before calling other methods on this annotation visitor</i>. * before calling other methods on this annotation visitor</i>.
*/ */
public AnnotationVisitor visitAnnotation(String name, String desc) { public AnnotationVisitor visitAnnotation(String name, String desc) {
if (av != null) { if (av != null) {
return av.visitAnnotation(name, desc); return av.visitAnnotation(name, desc);
} }
return null; return null;
} }
/** /**
* Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char, * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char,
* int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader} * int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader}
* does. * does.
* *
* @param name the value name. * @param name the value name.
* @return a visitor to visit the actual array value elements, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is * @return a visitor to visit the actual array value elements, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is
* not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are * not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are
* ignored. <i>All the array values must be visited before calling other methods on this annotation visitor</i>. * ignored. <i>All the array values must be visited before calling other methods on this annotation visitor</i>.
*/ */
public AnnotationVisitor visitArray(String name) { public AnnotationVisitor visitArray(String name) {
if (av != null) { if (av != null) {
return av.visitArray(name); return av.visitArray(name);
} }
return null; return null;
} }
/** Visits the end of the annotation. */ /** Visits the end of the annotation. */
public void visitEnd() { public void visitEnd() {
if (av != null) { if (av != null) {
av.visitEnd(); av.visitEnd();
} }
} }
} }

View File

@@ -66,301 +66,301 @@ package org.redkale.asm;
*/ */
final class AnnotationWriter extends AnnotationVisitor { final class AnnotationWriter extends AnnotationVisitor {
/** The class writer to which this annotation must be added. */ /** The class writer to which this annotation must be added. */
private final ClassWriter cw; private final ClassWriter cw;
/** The number of values in this annotation. */ /** The number of values in this annotation. */
private int size; private int size;
/** /**
* &#60;tt&#62;true&#60;tt&#62; if values are named, &#60;tt&#62;false&#60;/tt&#62; otherwise. Annotation writers * &#60;tt&#62;true&#60;tt&#62; if values are named, &#60;tt&#62;false&#60;/tt&#62; otherwise. Annotation writers
* used for annotation default and annotation arrays use unnamed values. * used for annotation default and annotation arrays use unnamed values.
*/ */
private final boolean named; private final boolean named;
/** /**
* The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of * The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of
* values must be stored as a unsigned short just before these bytes. * values must be stored as a unsigned short just before these bytes.
*/ */
private final ByteVector bv; private final ByteVector bv;
/** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */ /** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */
private final ByteVector parent; private final ByteVector parent;
/** Where the number of values of this annotation must be stored in {@link #parent}. */ /** Where the number of values of this annotation must be stored in {@link #parent}. */
private final int offset; private final int offset;
/** Next annotation writer. This field is used to store annotation lists. */ /** Next annotation writer. This field is used to store annotation lists. */
AnnotationWriter next; AnnotationWriter next;
/** Previous annotation writer. This field is used to store annotation lists. */ /** Previous annotation writer. This field is used to store annotation lists. */
AnnotationWriter prev; AnnotationWriter prev;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Constructor // Constructor
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Constructs a new {@link AnnotationWriter}. * Constructs a new {@link AnnotationWriter}.
* *
* @param cw the class writer to which this annotation must be added. * @param cw the class writer to which this annotation must be added.
* @param named &#60;tt&#62;true&#60;tt&#62; if values are named, &#60;tt&#62;false&#60;/tt&#62; otherwise. * @param named &#60;tt&#62;true&#60;tt&#62; if values are named, &#60;tt&#62;false&#60;/tt&#62; otherwise.
* @param bv where the annotation values must be stored. * @param bv where the annotation values must be stored.
* @param parent where the number of annotation values must be stored. * @param parent where the number of annotation values must be stored.
* @param offset where in &#60;tt&#62;parent&#60;/tt&#62; the number of annotation values must be stored. * @param offset where in &#60;tt&#62;parent&#60;/tt&#62; the number of annotation values must be stored.
*/ */
AnnotationWriter( AnnotationWriter(
final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) { final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) {
super(Opcodes.ASM6); super(Opcodes.ASM6);
this.cw = cw; this.cw = cw;
this.named = named; this.named = named;
this.bv = bv; this.bv = bv;
this.parent = parent; this.parent = parent;
this.offset = offset; this.offset = offset;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Implementation of the AnnotationVisitor abstract class // Implementation of the AnnotationVisitor abstract class
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@Override @Override
public void visit(final String name, final Object value) { public void visit(final String name, final Object value) {
++size; ++size;
if (named) { if (named) {
bv.putShort(cw.newUTF8(name)); bv.putShort(cw.newUTF8(name));
} }
if (value instanceof String) { if (value instanceof String) {
bv.put12('s', cw.newUTF8((String) value)); bv.put12('s', cw.newUTF8((String) value));
} else if (value instanceof Byte) { } else if (value instanceof Byte) {
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
} else if (value instanceof Boolean) { } else if (value instanceof Boolean) {
int v = ((Boolean) value).booleanValue() ? 1 : 0; int v = ((Boolean) value).booleanValue() ? 1 : 0;
bv.put12('Z', cw.newInteger(v).index); bv.put12('Z', cw.newInteger(v).index);
} else if (value instanceof Character) { } else if (value instanceof Character) {
bv.put12('C', cw.newInteger(((Character) value).charValue()).index); bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
} else if (value instanceof Short) { } else if (value instanceof Short) {
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
} else if (value instanceof Type) { } else if (value instanceof Type) {
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
} else if (value instanceof byte[]) { } else if (value instanceof byte[]) {
byte[] v = (byte[]) value; byte[] v = (byte[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('B', cw.newInteger(v[i]).index); bv.put12('B', cw.newInteger(v[i]).index);
} }
} else if (value instanceof boolean[]) { } else if (value instanceof boolean[]) {
boolean[] v = (boolean[]) value; boolean[] v = (boolean[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
} }
} else if (value instanceof short[]) { } else if (value instanceof short[]) {
short[] v = (short[]) value; short[] v = (short[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('S', cw.newInteger(v[i]).index); bv.put12('S', cw.newInteger(v[i]).index);
} }
} else if (value instanceof char[]) { } else if (value instanceof char[]) {
char[] v = (char[]) value; char[] v = (char[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('C', cw.newInteger(v[i]).index); bv.put12('C', cw.newInteger(v[i]).index);
} }
} else if (value instanceof int[]) { } else if (value instanceof int[]) {
int[] v = (int[]) value; int[] v = (int[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('I', cw.newInteger(v[i]).index); bv.put12('I', cw.newInteger(v[i]).index);
} }
} else if (value instanceof long[]) { } else if (value instanceof long[]) {
long[] v = (long[]) value; long[] v = (long[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('J', cw.newLong(v[i]).index); bv.put12('J', cw.newLong(v[i]).index);
} }
} else if (value instanceof float[]) { } else if (value instanceof float[]) {
float[] v = (float[]) value; float[] v = (float[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('F', cw.newFloat(v[i]).index); bv.put12('F', cw.newFloat(v[i]).index);
} }
} else if (value instanceof double[]) { } else if (value instanceof double[]) {
double[] v = (double[]) value; double[] v = (double[]) value;
bv.put12('[', v.length); bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) { for (int i = 0; i < v.length; i++) {
bv.put12('D', cw.newDouble(v[i]).index); bv.put12('D', cw.newDouble(v[i]).index);
} }
} else { } else {
Item i = cw.newConstItem(value); Item i = cw.newConstItem(value);
bv.put12(".s.IFJDCS".charAt(i.type), i.index); bv.put12(".s.IFJDCS".charAt(i.type), i.index);
} }
} }
@Override @Override
public void visitEnum(final String name, final String desc, final String value) { public void visitEnum(final String name, final String desc, final String value) {
++size; ++size;
if (named) { if (named) {
bv.putShort(cw.newUTF8(name)); bv.putShort(cw.newUTF8(name));
} }
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
} }
@Override @Override
public AnnotationVisitor visitAnnotation(final String name, final String desc) { public AnnotationVisitor visitAnnotation(final String name, final String desc) {
++size; ++size;
if (named) { if (named) {
bv.putShort(cw.newUTF8(name)); bv.putShort(cw.newUTF8(name));
} }
// write tag and type, and reserve space for values count // write tag and type, and reserve space for values count
bv.put12('@', cw.newUTF8(desc)).putShort(0); bv.put12('@', cw.newUTF8(desc)).putShort(0);
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
} }
@Override @Override
public AnnotationVisitor visitArray(final String name) { public AnnotationVisitor visitArray(final String name) {
++size; ++size;
if (named) { if (named) {
bv.putShort(cw.newUTF8(name)); bv.putShort(cw.newUTF8(name));
} }
// write tag, and reserve space for array size // write tag, and reserve space for array size
bv.put12('[', 0); bv.put12('[', 0);
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
if (parent != null) { if (parent != null) {
byte[] data = parent.data; byte[] data = parent.data;
data[offset] = (byte) (size >>> 8); data[offset] = (byte) (size >>> 8);
data[offset + 1] = (byte) size; data[offset + 1] = (byte) size;
} }
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Utility methods // Utility methods
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Returns the size of this annotation writer list. * Returns the size of this annotation writer list.
* *
* @return the size of this annotation writer list. * @return the size of this annotation writer list.
*/ */
int getSize() { int getSize() {
int size = 0; int size = 0;
AnnotationWriter aw = this; AnnotationWriter aw = this;
while (aw != null) { while (aw != null) {
size += aw.bv.length; size += aw.bv.length;
aw = aw.next; aw = aw.next;
} }
return size; return size;
} }
/** /**
* Puts the annotations of this annotation writer list into the given byte vector. * Puts the annotations of this annotation writer list into the given byte vector.
* *
* @param out where the annotations must be put. * @param out where the annotations must be put.
*/ */
void put(final ByteVector out) { void put(final ByteVector out) {
int n = 0; int n = 0;
int size = 2; int size = 2;
AnnotationWriter aw = this; AnnotationWriter aw = this;
AnnotationWriter last = null; AnnotationWriter last = null;
while (aw != null) { while (aw != null) {
++n; ++n;
size += aw.bv.length; size += aw.bv.length;
aw.visitEnd(); // in case user forgot to call visitEnd aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last; aw.prev = last;
last = aw; last = aw;
aw = aw.next; aw = aw.next;
} }
out.putInt(size); out.putInt(size);
out.putShort(n); out.putShort(n);
aw = last; aw = last;
while (aw != null) { while (aw != null) {
out.putByteArray(aw.bv.data, 0, aw.bv.length); out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev; aw = aw.prev;
} }
} }
/** /**
* Puts the given annotation lists into the given byte vector. * Puts the given annotation lists into the given byte vector.
* *
* @param panns an array of annotation writer lists. * @param panns an array of annotation writer lists.
* @param off index of the first annotation to be written. * @param off index of the first annotation to be written.
* @param out where the annotations must be put. * @param out where the annotations must be put.
*/ */
static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) { static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) {
int size = 1 + 2 * (panns.length - off); int size = 1 + 2 * (panns.length - off);
for (int i = off; i < panns.length; ++i) { for (int i = off; i < panns.length; ++i) {
size += panns[i] == null ? 0 : panns[i].getSize(); size += panns[i] == null ? 0 : panns[i].getSize();
} }
out.putInt(size).putByte(panns.length - off); out.putInt(size).putByte(panns.length - off);
for (int i = off; i < panns.length; ++i) { for (int i = off; i < panns.length; ++i) {
AnnotationWriter aw = panns[i]; AnnotationWriter aw = panns[i];
AnnotationWriter last = null; AnnotationWriter last = null;
int n = 0; int n = 0;
while (aw != null) { while (aw != null) {
++n; ++n;
aw.visitEnd(); // in case user forgot to call visitEnd aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last; aw.prev = last;
last = aw; last = aw;
aw = aw.next; aw = aw.next;
} }
out.putShort(n); out.putShort(n);
aw = last; aw = last;
while (aw != null) { while (aw != null) {
out.putByteArray(aw.bv.data, 0, aw.bv.length); out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev; aw = aw.prev;
} }
} }
} }
/** /**
* Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE * Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE
* target types are not supported. * target types are not supported.
* *
* @param typeRef a reference to the annotated type. See {@link TypeReference}. * @param typeRef a reference to the annotated type. See {@link TypeReference}.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
* within 'typeRef'. May be &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole. * within 'typeRef'. May be &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param out where the type reference and type path must be put. * @param out where the type reference and type path must be put.
*/ */
static void putTarget(int typeRef, TypePath typePath, ByteVector out) { static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
switch (typeRef >>> 24) { switch (typeRef >>> 24) {
case 0x00: // CLASS_TYPE_PARAMETER case 0x00: // CLASS_TYPE_PARAMETER
case 0x01: // METHOD_TYPE_PARAMETER case 0x01: // METHOD_TYPE_PARAMETER
case 0x16: // METHOD_FORMAL_PARAMETER case 0x16: // METHOD_FORMAL_PARAMETER
out.putShort(typeRef >>> 16); out.putShort(typeRef >>> 16);
break; break;
case 0x13: // FIELD case 0x13: // FIELD
case 0x14: // METHOD_RETURN case 0x14: // METHOD_RETURN
case 0x15: // METHOD_RECEIVER case 0x15: // METHOD_RECEIVER
out.putByte(typeRef >>> 24); out.putByte(typeRef >>> 24);
break; break;
case 0x47: // CAST case 0x47: // CAST
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
out.putInt(typeRef); out.putInt(typeRef);
break; break;
// case 0x10: // CLASS_EXTENDS // case 0x10: // CLASS_EXTENDS
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
// case 0x17: // THROWS // case 0x17: // THROWS
// case 0x42: // EXCEPTION_PARAMETER // case 0x42: // EXCEPTION_PARAMETER
// case 0x43: // INSTANCEOF // case 0x43: // INSTANCEOF
// case 0x44: // NEW // case 0x44: // NEW
// case 0x45: // CONSTRUCTOR_REFERENCE // case 0x45: // CONSTRUCTOR_REFERENCE
// case 0x46: // METHOD_REFERENCE // case 0x46: // METHOD_REFERENCE
default: default:
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8); out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
break; break;
} }
if (typePath == null) { if (typePath == null) {
out.putByte(0); out.putByte(0);
} else { } else {
int length = typePath.b[typePath.offset] * 2 + 1; int length = typePath.b[typePath.offset] * 2 + 1;
out.putByteArray(typePath.b, typePath.offset, length); out.putByteArray(typePath.b, typePath.offset, length);
} }
} }
} }

View File

@@ -17,124 +17,124 @@ import org.redkale.convert.json.JsonConvert;
*/ */
public class AsmMethodBean { public class AsmMethodBean {
private List<AsmMethodParam> params; private List<AsmMethodParam> params;
private int access; private int access;
private String name; private String name;
private String desc; private String desc;
private String signature; private String signature;
private String[] exceptions; private String[] exceptions;
public AsmMethodBean() {} public AsmMethodBean() {}
public AsmMethodBean(int access, String name, String desc, String signature, String[] exceptions) { public AsmMethodBean(int access, String name, String desc, String signature, String[] exceptions) {
this.access = access; this.access = access;
this.name = name; this.name = name;
this.desc = desc; this.desc = desc;
this.signature = signature; this.signature = signature;
this.exceptions = exceptions; this.exceptions = exceptions;
this.params = new ArrayList<>(); this.params = new ArrayList<>();
} }
public static AsmMethodBean get(Map<String, AsmMethodBean> map, Method method) { public static AsmMethodBean get(Map<String, AsmMethodBean> map, Method method) {
return map == null ? null : map.get(method.getName() + ":" + Type.getMethodDescriptor(method)); return map == null ? null : map.get(method.getName() + ":" + Type.getMethodDescriptor(method));
} }
void removeEmptyNames() { void removeEmptyNames() {
if (params != null) { if (params != null) {
List<AsmMethodParam> dels = null; List<AsmMethodParam> dels = null;
for (AsmMethodParam p : params) { for (AsmMethodParam p : params) {
if (" ".equals(p.getName())) { if (" ".equals(p.getName())) {
if (dels == null) { if (dels == null) {
dels = new ArrayList<>(); dels = new ArrayList<>();
} }
dels.add(p); dels.add(p);
} }
} }
if (dels != null) { if (dels != null) {
for (AsmMethodParam p : dels) { for (AsmMethodParam p : dels) {
params.remove(p); params.remove(p);
} }
} }
} }
} }
public List<String> fieldNameList() { public List<String> fieldNameList() {
if (params == null) { if (params == null) {
return new ArrayList<>(); return new ArrayList<>();
} }
List<String> rs = new ArrayList<>(params.size()); List<String> rs = new ArrayList<>(params.size());
for (AsmMethodParam p : params) { for (AsmMethodParam p : params) {
rs.add(p.getName()); rs.add(p.getName());
} }
return rs; return rs;
} }
public String[] fieldNameArray() { public String[] fieldNameArray() {
if (params == null) { if (params == null) {
return null; return null;
} }
String[] rs = new String[params.size()]; String[] rs = new String[params.size()];
for (int i = 0; i < rs.length; i++) { for (int i = 0; i < rs.length; i++) {
rs[i] = params.get(i).getName(); rs[i] = params.get(i).getName();
} }
return rs; return rs;
} }
public List<AsmMethodParam> getParams() { public List<AsmMethodParam> getParams() {
return params; return params;
} }
public void setParams(List<AsmMethodParam> params) { public void setParams(List<AsmMethodParam> params) {
this.params = params; this.params = params;
} }
public int getAccess() { public int getAccess() {
return access; return access;
} }
public void setAccess(int access) { public void setAccess(int access) {
this.access = access; this.access = access;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public String getDesc() { public String getDesc() {
return desc; return desc;
} }
public void setDesc(String desc) { public void setDesc(String desc) {
this.desc = desc; this.desc = desc;
} }
public String getSignature() { public String getSignature() {
return signature; return signature;
} }
public void setSignature(String signature) { public void setSignature(String signature) {
this.signature = signature; this.signature = signature;
} }
public String[] getExceptions() { public String[] getExceptions() {
return exceptions; return exceptions;
} }
public void setExceptions(String[] exceptions) { public void setExceptions(String[] exceptions) {
this.exceptions = exceptions; this.exceptions = exceptions;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }

View File

@@ -40,370 +40,370 @@ import org.redkale.util.Utility;
*/ */
public abstract class AsmMethodBoost<T> { public abstract class AsmMethodBoost<T> {
protected final AtomicInteger fieldIndex = new AtomicInteger(); protected final AtomicInteger fieldIndex = new AtomicInteger();
protected final boolean remote; protected final boolean remote;
protected final Class serviceType; protected final Class serviceType;
protected AsmMethodBoost(boolean remote, Class serviceType) { protected AsmMethodBoost(boolean remote, Class serviceType) {
this.remote = remote; this.remote = remote;
this.serviceType = serviceType; this.serviceType = serviceType;
} }
public static AsmMethodBoost create(boolean remote, Collection<AsmMethodBoost> list) { public static AsmMethodBoost create(boolean remote, Collection<AsmMethodBoost> list) {
return new AsmMethodBoosts(remote, list); return new AsmMethodBoosts(remote, list);
} }
public static AsmMethodBoost create(boolean remote, AsmMethodBoost... items) { public static AsmMethodBoost create(boolean remote, AsmMethodBoost... items) {
return new AsmMethodBoosts(remote, items); return new AsmMethodBoosts(remote, items);
} }
/** /**
* 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method) * 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method)
* *
* @param clazz Class * @param clazz Class
* @return Map * @return Map
*/ */
public static Map<String, AsmMethodBean> getMethodBeans(Class clazz) { public static Map<String, AsmMethodBean> getMethodBeans(Class clazz) {
Map<String, AsmMethodBean> rs = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), clazz); Map<String, AsmMethodBean> rs = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), clazz);
// 返回的List中参数列表可能会比方法参数量多因为方法内的临时变量也会存入list中 所以需要list的元素集合比方法的参数多 // 返回的List中参数列表可能会比方法参数量多因为方法内的临时变量也会存入list中 所以需要list的元素集合比方法的参数多
rs.values().forEach(AsmMethodBean::removeEmptyNames); rs.values().forEach(AsmMethodBean::removeEmptyNames);
return rs; return rs;
} }
public static String getMethodBeanKey(Method method) { public static String getMethodBeanKey(Method method) {
return method.getName() + ":" + Type.getMethodDescriptor(method); return method.getName() + ":" + Type.getMethodDescriptor(method);
} }
/** /**
* 获取需屏蔽的方法上的注解 * 获取需屏蔽的方法上的注解
* *
* @param method 方法 * @param method 方法
* @return 需要屏蔽的注解 * @return 需要屏蔽的注解
*/ */
public abstract List<Class<? extends Annotation>> filterMethodAnnotations(Method method); public abstract List<Class<? extends Annotation>> filterMethodAnnotations(Method method);
/** /**
* 对方法进行动态加强处理 * 对方法进行动态加强处理
* *
* @param classLoader ClassLoader * @param classLoader ClassLoader
* @param cw 动态字节码Writer * @param cw 动态字节码Writer
* @param newDynName 动态新类名 * @param newDynName 动态新类名
* @param fieldPrefix 动态字段的前缀 * @param fieldPrefix 动态字段的前缀
* @param filterAnns 需要过滤的注解 * @param filterAnns 需要过滤的注解
* @param method 操作的方法 * @param method 操作的方法
* @param newMethodName 新的方法名, 可能为null * @param newMethodName 新的方法名, 可能为null
* @return 下一个新的方法名不做任何处理应返回参数newMethodName * @return 下一个新的方法名不做任何处理应返回参数newMethodName
*/ */
public abstract String doMethod( public abstract String doMethod(
ClassLoader classLoader, ClassLoader classLoader,
ClassWriter cw, ClassWriter cw,
String newDynName, String newDynName,
String fieldPrefix, String fieldPrefix,
List<Class<? extends Annotation>> filterAnns, List<Class<? extends Annotation>> filterAnns,
Method method, Method method,
@Nullable String newMethodName); @Nullable String newMethodName);
/** /**
* 处理所有动态方法后调用 * 处理所有动态方法后调用
* *
* @param classLoader ClassLoader * @param classLoader ClassLoader
* @param cw 动态字节码Writer * @param cw 动态字节码Writer
* @param newDynName 动态新类名 * @param newDynName 动态新类名
* @param fieldPrefix 动态字段的前缀 * @param fieldPrefix 动态字段的前缀
*/ */
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {} public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {}
/** /**
* 实例对象进行操作,通常用于给动态的字段赋值 * 实例对象进行操作,通常用于给动态的字段赋值
* *
* @param resourceFactory ResourceFactory * @param resourceFactory ResourceFactory
* @param service 实例对象 * @param service 实例对象
*/ */
public abstract void doInstance(ResourceFactory resourceFactory, T service); public abstract void doInstance(ResourceFactory resourceFactory, T service);
protected AsmMethodBean getMethodBean(Method method) { protected AsmMethodBean getMethodBean(Method method) {
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(serviceType); Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
return AsmMethodBean.get(methodBeans, method); return AsmMethodBean.get(methodBeans, method);
} }
protected MethodVisitor createMethodVisitor( protected MethodVisitor createMethodVisitor(
ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) { ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) {
return new MethodDebugVisitor(cw.visitMethod( return new MethodDebugVisitor(cw.visitMethod(
getAcc(method, newMethodName), getAcc(method, newMethodName),
getNowMethodName(method, newMethodName), getNowMethodName(method, newMethodName),
Type.getMethodDescriptor(method), Type.getMethodDescriptor(method),
getMethodSignature(method, methodBean), getMethodSignature(method, methodBean),
getMethodExceptions(method, methodBean))); getMethodExceptions(method, methodBean)));
} }
protected int getAcc(Method method, String newMethodName) { protected int getAcc(Method method, String newMethodName) {
if (newMethodName != null) { if (newMethodName != null) {
return ACC_PRIVATE; return ACC_PRIVATE;
} }
return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC; return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC;
} }
protected String getNowMethodName(Method method, String newMethodName) { protected String getNowMethodName(Method method, String newMethodName) {
return newMethodName == null ? method.getName() : newMethodName; return newMethodName == null ? method.getName() : newMethodName;
} }
protected String getMethodSignature(Method method, AsmMethodBean methodBean) { protected String getMethodSignature(Method method, AsmMethodBean methodBean) {
return methodBean != null ? methodBean.getSignature() : null; return methodBean != null ? methodBean.getSignature() : null;
} }
protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) { protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) {
if (methodBean == null) { if (methodBean == null) {
String[] exceptions = null; String[] exceptions = null;
Class<?>[] expTypes = method.getExceptionTypes(); Class<?>[] expTypes = method.getExceptionTypes();
if (expTypes.length > 0) { if (expTypes.length > 0) {
exceptions = new String[expTypes.length]; exceptions = new String[expTypes.length];
for (int i = 0; i < expTypes.length; i++) { for (int i = 0; i < expTypes.length; i++) {
exceptions[i] = expTypes[i].getName().replace('.', '/'); exceptions[i] = expTypes[i].getName().replace('.', '/');
} }
} }
return exceptions; return exceptions;
} else { } else {
return methodBean.getExceptions(); return methodBean.getExceptions();
} }
} }
protected void visitRawAnnotation( protected void visitRawAnnotation(
Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) { Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) {
if (newMethodName == null) { if (newMethodName == null) {
// 给方法加上原有的Annotation // 给方法加上原有的Annotation
final Annotation[] anns = method.getAnnotations(); final Annotation[] anns = method.getAnnotations();
for (Annotation ann : anns) { for (Annotation ann : anns) {
if (ann.annotationType() != selfAnnType if (ann.annotationType() != selfAnnType
&& (filterAnns == null || !filterAnns.contains(ann.annotationType()))) { && (filterAnns == null || !filterAnns.contains(ann.annotationType()))) {
Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
} }
} }
// 给参数加上原有的Annotation // 给参数加上原有的Annotation
final Annotation[][] annss = method.getParameterAnnotations(); final Annotation[][] annss = method.getParameterAnnotations();
for (int k = 0; k < annss.length; k++) { for (int k = 0; k < annss.length; k++) {
for (Annotation ann : annss[k]) { for (Annotation ann : annss[k]) {
Asms.visitAnnotation( Asms.visitAnnotation(
mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
} }
} }
} }
} }
protected List<Integer> visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) { protected List<Integer> visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) {
// 传参数 // 传参数
Class[] paramTypes = method.getParameterTypes(); Class[] paramTypes = method.getParameterTypes();
List<Integer> insns = new ArrayList<>(); List<Integer> insns = new ArrayList<>();
for (Class pt : paramTypes) { for (Class pt : paramTypes) {
insn++; insn++;
if (pt.isPrimitive()) { if (pt.isPrimitive()) {
if (pt == long.class) { if (pt == long.class) {
mv.visitVarInsn(LLOAD, insn++); mv.visitVarInsn(LLOAD, insn++);
} else if (pt == float.class) { } else if (pt == float.class) {
mv.visitVarInsn(FLOAD, insn++); mv.visitVarInsn(FLOAD, insn++);
} else if (pt == double.class) { } else if (pt == double.class) {
mv.visitVarInsn(DLOAD, insn++); mv.visitVarInsn(DLOAD, insn++);
} else { } else {
mv.visitVarInsn(ILOAD, insn); mv.visitVarInsn(ILOAD, insn);
} }
} else { } else {
mv.visitVarInsn(ALOAD, insn); mv.visitVarInsn(ALOAD, insn);
} }
insns.add(insn); insns.add(insn);
} }
return insns; return insns;
} }
protected void visitParamTypesLocalVariable( protected void visitParamTypesLocalVariable(
MethodVisitor mv, Method method, Label l0, Label l2, List<Integer> insns, AsmMethodBean methodBean) { MethodVisitor mv, Method method, Label l0, Label l2, List<Integer> insns, AsmMethodBean methodBean) {
Class[] paramTypes = method.getParameterTypes(); Class[] paramTypes = method.getParameterTypes();
if (methodBean != null && paramTypes.length > 0) { if (methodBean != null && paramTypes.length > 0) {
mv.visitLabel(l2); mv.visitLabel(l2);
List<AsmMethodParam> params = methodBean.getParams(); List<AsmMethodParam> params = methodBean.getParams();
for (int i = 0; i < paramTypes.length; i++) { for (int i = 0; i < paramTypes.length; i++) {
AsmMethodParam param = params.get(i); AsmMethodParam param = params.get(i);
mv.visitLocalVariable( mv.visitLocalVariable(
param.getName(), param.getName(),
param.description(paramTypes[i]), param.description(paramTypes[i]),
param.signature(paramTypes[i]), param.signature(paramTypes[i]),
l0, l0,
l2, l2,
insns.get(i)); insns.get(i));
} }
} }
} }
protected void visitInsnReturn( protected void visitInsnReturn(
MethodVisitor mv, Method method, Label l0, List<Integer> insns, AsmMethodBean methodBean) { MethodVisitor mv, Method method, Label l0, List<Integer> insns, AsmMethodBean methodBean) {
if (method.getGenericReturnType() == void.class) { if (method.getGenericReturnType() == void.class) {
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
} else { } else {
Class returnclz = method.getReturnType(); Class returnclz = method.getReturnType();
if (returnclz.isPrimitive()) { if (returnclz.isPrimitive()) {
if (returnclz == long.class) { if (returnclz == long.class) {
mv.visitInsn(LRETURN); mv.visitInsn(LRETURN);
} else if (returnclz == float.class) { } else if (returnclz == float.class) {
mv.visitInsn(FRETURN); mv.visitInsn(FRETURN);
} else if (returnclz == double.class) { } else if (returnclz == double.class) {
mv.visitInsn(DRETURN); mv.visitInsn(DRETURN);
} else { } else {
mv.visitInsn(IRETURN); mv.visitInsn(IRETURN);
} }
} else { } else {
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
} }
} }
visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean); visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean);
} }
/** /**
* 生产动态字节码的方法扩展器, 可以进行方法加强动作 * 生产动态字节码的方法扩展器, 可以进行方法加强动作
* *
* @param <T> 泛型 * @param <T> 泛型
* @since 2.8.0 * @since 2.8.0
*/ */
static class AsmMethodBoosts<T> extends AsmMethodBoost<T> { static class AsmMethodBoosts<T> extends AsmMethodBoost<T> {
private final AsmMethodBoost[] items; private final AsmMethodBoost[] items;
public AsmMethodBoosts(boolean remote, Collection<AsmMethodBoost> list) { public AsmMethodBoosts(boolean remote, Collection<AsmMethodBoost> list) {
super(remote, null); super(remote, null);
this.items = list.toArray(new AsmMethodBoost[list.size()]); this.items = list.toArray(new AsmMethodBoost[list.size()]);
} }
public AsmMethodBoosts(boolean remote, AsmMethodBoost... items) { public AsmMethodBoosts(boolean remote, AsmMethodBoost... items) {
super(remote, null); super(remote, null);
this.items = items; this.items = items;
} }
@Override @Override
public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) { public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) {
List<Class<? extends Annotation>> list = null; List<Class<? extends Annotation>> list = null;
for (AsmMethodBoost item : items) { for (AsmMethodBoost item : items) {
if (item != null) { if (item != null) {
List<Class<? extends Annotation>> sub = item.filterMethodAnnotations(method); List<Class<? extends Annotation>> sub = item.filterMethodAnnotations(method);
if (sub != null) { if (sub != null) {
if (list == null) { if (list == null) {
list = new ArrayList<>(); list = new ArrayList<>();
} }
list.addAll(sub); list.addAll(sub);
} }
} }
} }
return list; return list;
} }
@Override @Override
public String doMethod( public String doMethod(
ClassLoader classLoader, ClassLoader classLoader,
ClassWriter cw, ClassWriter cw,
String newDynName, String newDynName,
String fieldPrefix, String fieldPrefix,
List<Class<? extends Annotation>> filterAnns, List<Class<? extends Annotation>> filterAnns,
Method method, Method method,
String newMethodName) { String newMethodName) {
String newName = newMethodName; String newName = newMethodName;
for (AsmMethodBoost item : items) { for (AsmMethodBoost item : items) {
if (item != null) { if (item != null) {
newName = item.doMethod(classLoader, cw, newDynName, fieldPrefix, filterAnns, method, newName); newName = item.doMethod(classLoader, cw, newDynName, fieldPrefix, filterAnns, method, newName);
} }
} }
return newName; return newName;
} }
@Override @Override
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) { public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {
for (AsmMethodBoost item : items) { for (AsmMethodBoost item : items) {
if (item != null) { if (item != null) {
item.doAfterMethods(classLoader, cw, newDynName, fieldPrefix); item.doAfterMethods(classLoader, cw, newDynName, fieldPrefix);
} }
} }
} }
@Override @Override
public void doInstance(ResourceFactory resourceFactory, T service) { public void doInstance(ResourceFactory resourceFactory, T service) {
for (AsmMethodBoost item : items) { for (AsmMethodBoost item : items) {
if (item != null) { if (item != null) {
item.doInstance(resourceFactory, service); item.doInstance(resourceFactory, service);
} }
} }
} }
} }
static class MethodParamClassVisitor extends ClassVisitor { static class MethodParamClassVisitor extends ClassVisitor {
private Class serviceType; private Class serviceType;
private final Map<String, AsmMethodBean> methodBeanMap; private final Map<String, AsmMethodBean> methodBeanMap;
public MethodParamClassVisitor(int api, Class serviceType, final Map<String, AsmMethodBean> methodBeanMap) { public MethodParamClassVisitor(int api, Class serviceType, final Map<String, AsmMethodBean> methodBeanMap) {
super(api); super(api);
this.serviceType = serviceType; this.serviceType = serviceType;
this.methodBeanMap = methodBeanMap; this.methodBeanMap = methodBeanMap;
} }
@Override @Override
public MethodVisitor visitMethod( public MethodVisitor visitMethod(
int methodAccess, int methodAccess,
String methodName, String methodName,
String methodDesc, String methodDesc,
String methodSignature, String methodSignature,
String[] methodExceptions) { String[] methodExceptions) {
super.visitMethod(api, methodName, methodDesc, methodSignature, methodExceptions); super.visitMethod(api, methodName, methodDesc, methodSignature, methodExceptions);
if (java.lang.reflect.Modifier.isStatic(methodAccess)) { if (java.lang.reflect.Modifier.isStatic(methodAccess)) {
return null; return null;
} }
String key = methodName + ":" + methodDesc; String key = methodName + ":" + methodDesc;
if (methodBeanMap.containsKey(key)) { if (methodBeanMap.containsKey(key)) {
return null; return null;
} }
AsmMethodBean bean = AsmMethodBean bean =
new AsmMethodBean(methodAccess, methodName, methodDesc, methodSignature, methodExceptions); new AsmMethodBean(methodAccess, methodName, methodDesc, methodSignature, methodExceptions);
List<AsmMethodParam> paramList = bean.getParams(); List<AsmMethodParam> paramList = bean.getParams();
methodBeanMap.put(key, bean); methodBeanMap.put(key, bean);
return new MethodVisitor(Opcodes.ASM6) { return new MethodVisitor(Opcodes.ASM6) {
@Override @Override
public void visitParameter(String paramName, int paramAccess) { public void visitParameter(String paramName, int paramAccess) {
paramList.add(new AsmMethodParam(paramName)); paramList.add(new AsmMethodParam(paramName));
} }
@Override @Override
public void visitLocalVariable( public void visitLocalVariable(
String varName, String varDesc, String varSignature, Label start, Label end, int varIndex) { String varName, String varDesc, String varSignature, Label start, Label end, int varIndex) {
if (varIndex < 1) { if (varIndex < 1) {
return; return;
} }
int size = paramList.size(); int size = paramList.size();
// index并不会按顺序执行 // index并不会按顺序执行
if (varIndex > size) { if (varIndex > size) {
for (int i = size; i < varIndex; i++) { for (int i = size; i < varIndex; i++) {
paramList.add(new AsmMethodParam(" ", varDesc, varSignature)); paramList.add(new AsmMethodParam(" ", varDesc, varSignature));
} }
paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature)); paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature));
} }
paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature)); paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature));
} }
}; };
} }
// 返回的List中参数列表可能会比方法参数量多因为方法内的临时变量也会存入list中 所以需要list的元素集合比方法的参数多 // 返回的List中参数列表可能会比方法参数量多因为方法内的临时变量也会存入list中 所以需要list的元素集合比方法的参数多
static Map<String, AsmMethodBean> getMethodParamNames(Map<String, AsmMethodBean> map, Class clazz) { static Map<String, AsmMethodBean> getMethodParamNames(Map<String, AsmMethodBean> map, Class clazz) {
String n = clazz.getName(); String n = clazz.getName();
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class"); InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
if (in == null) { if (in == null) {
return map; return map;
} }
try { try {
new ClassReader(Utility.readBytesThenClose(in)) new ClassReader(Utility.readBytesThenClose(in))
.accept(new MethodParamClassVisitor(Opcodes.ASM6, clazz, map), 0); .accept(new MethodParamClassVisitor(Opcodes.ASM6, clazz, map), 0);
} catch (Exception e) { // 无需理会 } catch (Exception e) { // 无需理会
} }
Class superClass = clazz.getSuperclass(); Class superClass = clazz.getSuperclass();
if (superClass == null || superClass == Object.class) { // 接口的getSuperclass为null if (superClass == null || superClass == Object.class) { // 接口的getSuperclass为null
return map; return map;
} }
return getMethodParamNames(map, superClass); return getMethodParamNames(map, superClass);
} }
} }
} }

View File

@@ -15,58 +15,58 @@ import org.redkale.util.TypeToken;
*/ */
public class AsmMethodParam { public class AsmMethodParam {
private String name; private String name;
private String description; private String description;
private String signature; private String signature;
public AsmMethodParam() {} public AsmMethodParam() {}
public AsmMethodParam(String name) { public AsmMethodParam(String name) {
this.name = name; this.name = name;
} }
public AsmMethodParam(String name, String description, String signature) { public AsmMethodParam(String name, String description, String signature) {
this.name = name; this.name = name;
this.description = description; this.description = description;
this.signature = signature; this.signature = signature;
} }
public String description(java.lang.reflect.Type type) { public String description(java.lang.reflect.Type type) {
return description == null ? Type.getDescriptor(TypeToken.typeToClass(type)) : description; return description == null ? Type.getDescriptor(TypeToken.typeToClass(type)) : description;
} }
public String signature(java.lang.reflect.Type type) { public String signature(java.lang.reflect.Type type) {
return signature; return signature;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public String getDescription() { public String getDescription() {
return description; return description;
} }
public void setDescription(String description) { public void setDescription(String description) {
this.description = description; this.description = description;
} }
public String getSignature() { public String getSignature() {
return signature; return signature;
} }
public void setSignature(String signature) { public void setSignature(String signature) {
this.signature = signature; this.signature = signature;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }

View File

@@ -25,173 +25,173 @@ import org.redkale.util.RedkaleException;
*/ */
public final class Asms { public final class Asms {
private Asms() {} private Asms() {}
public static Handle createLambdaMetaHandle() { public static Handle createLambdaMetaHandle() {
return new Handle( return new Handle(
Opcodes.H_INVOKESTATIC, Opcodes.H_INVOKESTATIC,
"java/lang/invoke/LambdaMetafactory", "java/lang/invoke/LambdaMetafactory",
"metafactory", "metafactory",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
false); false);
} }
public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) { public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
try { try {
for (Method anm : ann.annotationType().getMethods()) { for (Method anm : ann.annotationType().getMethods()) {
final String mname = anm.getName(); final String mname = anm.getName();
if ("equals".equals(mname) if ("equals".equals(mname)
|| "hashCode".equals(mname) || "hashCode".equals(mname)
|| "toString".equals(mname) || "toString".equals(mname)
|| "annotationType".equals(mname)) { || "annotationType".equals(mname)) {
continue; continue;
} }
final Object r = anm.invoke(ann); final Object r = anm.invoke(ann);
if (r instanceof String[]) { if (r instanceof String[]) {
AnnotationVisitor av1 = av.visitArray(mname); AnnotationVisitor av1 = av.visitArray(mname);
for (String item : (String[]) r) { for (String item : (String[]) r) {
av1.visit(null, item); av1.visit(null, item);
} }
av1.visitEnd(); av1.visitEnd();
} else if (r instanceof Class[]) { } else if (r instanceof Class[]) {
AnnotationVisitor av1 = av.visitArray(mname); AnnotationVisitor av1 = av.visitArray(mname);
for (Class item : (Class[]) r) { for (Class item : (Class[]) r) {
av1.visit(null, Type.getType(item)); av1.visit(null, Type.getType(item));
} }
av1.visitEnd(); av1.visitEnd();
} else if (r instanceof Enum[]) { } else if (r instanceof Enum[]) {
AnnotationVisitor av1 = av.visitArray(mname); AnnotationVisitor av1 = av.visitArray(mname);
for (Enum item : (Enum[]) r) { for (Enum item : (Enum[]) r) {
av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name()); av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
} }
av1.visitEnd(); av1.visitEnd();
} else if (r instanceof Annotation[]) { } else if (r instanceof Annotation[]) {
AnnotationVisitor av1 = av.visitArray(mname); AnnotationVisitor av1 = av.visitArray(mname);
for (Annotation item : (Annotation[]) r) { for (Annotation item : (Annotation[]) r) {
visitAnnotation( visitAnnotation(
av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())),
item); item);
} }
av1.visitEnd(); av1.visitEnd();
} else if (r instanceof Class) { } else if (r instanceof Class) {
av.visit(mname, Type.getType((Class) r)); av.visit(mname, Type.getType((Class) r));
} else if (r instanceof Enum) { } else if (r instanceof Enum) {
av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name()); av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
} else if (r instanceof Annotation) { } else if (r instanceof Annotation) {
visitAnnotation( visitAnnotation(
av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())),
(Annotation) r); (Annotation) r);
} else { } else {
av.visit(mname, r); av.visit(mname, r);
} }
} }
av.visitEnd(); av.visitEnd();
} catch (Exception e) { } catch (Exception e) {
throw new RedkaleException(e); throw new RedkaleException(e);
} }
} }
public static void visitInsn(MethodVisitor mv, int num) { public static void visitInsn(MethodVisitor mv, int num) {
if (num < 6) { if (num < 6) {
mv.visitInsn(ICONST_0 + num); mv.visitInsn(ICONST_0 + num);
} else if (num <= Byte.MAX_VALUE) { } else if (num <= Byte.MAX_VALUE) {
mv.visitIntInsn(BIPUSH, num); mv.visitIntInsn(BIPUSH, num);
} else if (num <= Short.MAX_VALUE) { } else if (num <= Short.MAX_VALUE) {
mv.visitIntInsn(SIPUSH, num); mv.visitIntInsn(SIPUSH, num);
} else { } else {
mv.visitLdcInsn(num); mv.visitLdcInsn(num);
} }
} }
public static void visitFieldInsn(MethodVisitor mv, Class clazz) { public static void visitFieldInsn(MethodVisitor mv, Class clazz) {
if (clazz == boolean.class) { if (clazz == boolean.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
} else if (clazz == byte.class) { } else if (clazz == byte.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
} else if (clazz == char.class) { } else if (clazz == char.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
} else if (clazz == short.class) { } else if (clazz == short.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
} else if (clazz == int.class) { } else if (clazz == int.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
} else if (clazz == float.class) { } else if (clazz == float.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
} else if (clazz == long.class) { } else if (clazz == long.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
} else if (clazz == double.class) { } else if (clazz == double.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
} else { } else {
mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz))); mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz)));
} }
} }
public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) { public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) {
if (clazz == boolean.class) { if (clazz == boolean.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
} else if (clazz == byte.class) { } else if (clazz == byte.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
} else if (clazz == short.class) { } else if (clazz == short.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
} else if (clazz == char.class) { } else if (clazz == char.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
} else if (clazz == int.class) { } else if (clazz == int.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
} else if (clazz == float.class) { } else if (clazz == float.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
} else if (clazz == long.class) { } else if (clazz == long.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
} else if (clazz == double.class) { } else if (clazz == double.class) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
} }
} }
public static void visitCheckCast(MethodVisitor mv, Class clazz) { public static void visitCheckCast(MethodVisitor mv, Class clazz) {
if (clazz == boolean.class) { if (clazz == boolean.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
} else if (clazz == byte.class) { } else if (clazz == byte.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte"); mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
} else if (clazz == short.class) { } else if (clazz == short.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Short"); mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
} else if (clazz == char.class) { } else if (clazz == char.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Character"); mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
} else if (clazz == int.class) { } else if (clazz == int.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
} else if (clazz == float.class) { } else if (clazz == float.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Float"); mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
} else if (clazz == long.class) { } else if (clazz == long.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
} else if (clazz == double.class) { } else if (clazz == double.class) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
} else { } else {
mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/')); mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/'));
} }
} }
public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) { public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) {
if (clazz == boolean.class) { if (clazz == boolean.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
} else if (clazz == byte.class) { } else if (clazz == byte.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
} else if (clazz == short.class) { } else if (clazz == short.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
} else if (clazz == char.class) { } else if (clazz == char.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
} else if (clazz == int.class) { } else if (clazz == int.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
} else if (clazz == float.class) { } else if (clazz == float.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
} else if (clazz == long.class) { } else if (clazz == long.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
} else if (clazz == double.class) { } else if (clazz == double.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
} }
} }
} }

View File

@@ -68,245 +68,245 @@ import java.util.Arrays;
*/ */
public class Attribute { public class Attribute {
/** The type of this attribute. */ /** The type of this attribute. */
public final String type; public final String type;
/** The raw value of this attribute, used only for unknown attributes. */ /** The raw value of this attribute, used only for unknown attributes. */
byte[] value; byte[] value;
/** The next attribute in this attribute list. May be &#60;tt&#62;null&#60;/tt&#62;. */ /** The next attribute in this attribute list. May be &#60;tt&#62;null&#60;/tt&#62;. */
Attribute next; Attribute next;
/** /**
* Constructs a new empty attribute. * Constructs a new empty attribute.
* *
* @param type the type of the attribute. * @param type the type of the attribute.
*/ */
protected Attribute(final String type) { protected Attribute(final String type) {
this.type = type; this.type = type;
} }
/** /**
* Returns &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is unknown. The default implementation of this * Returns &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is unknown. The default implementation of this
* method always returns &#60;tt&#62;true&#60;/tt&#62;. * method always returns &#60;tt&#62;true&#60;/tt&#62;.
* *
* @return &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is unknown. * @return &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is unknown.
*/ */
public boolean isUnknown() { public boolean isUnknown() {
return true; return true;
} }
/** /**
* Returns &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is a code attribute. * Returns &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is a code attribute.
* *
* @return &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is a code attribute. * @return &#60;tt&#62;true&#60;/tt&#62; if this type of attribute is a code attribute.
*/ */
public boolean isCodeAttribute() { public boolean isCodeAttribute() {
return false; return false;
} }
/** /**
* Returns the labels corresponding to this attribute. * Returns the labels corresponding to this attribute.
* *
* @return the labels corresponding to this attribute, or &#60;tt&#62;null&#60;/tt&#62; if this attribute is not a * @return the labels corresponding to this attribute, or &#60;tt&#62;null&#60;/tt&#62; if this attribute is not a
* code attribute that contains labels. * code attribute that contains labels.
*/ */
protected Label[] getLabels() { protected Label[] getLabels() {
return null; return null;
} }
/** /**
* Reads a {@link #type type} attribute. This method must return a <i>new</i> {@link Attribute} object, of type * Reads a {@link #type type} attribute. This method must return a <i>new</i> {@link Attribute} object, of type
* {@link #type type}, corresponding to the &#60;tt&#62;len&#60;/tt&#62; bytes starting at the given offset, in the * {@link #type type}, corresponding to the &#60;tt&#62;len&#60;/tt&#62; bytes starting at the given offset, in the
* given class reader. * given class reader.
* *
* @param cr the class that contains the attribute to be read. * @param cr the class that contains the attribute to be read.
* @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute * @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute
* header bytes, containing the type and the length of the attribute, are not taken into account here. * header bytes, containing the type and the length of the attribute, are not taken into account here.
* @param len the length of the attribute's content. * @param len the length of the attribute's content.
* @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8}, * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8},
* {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}. * {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}.
* @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the * @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the
* attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the * attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the
* length of the attribute, are not taken into account here. * length of the attribute, are not taken into account here.
* @param labels the labels of the method's code, or &#60;tt&#62;null&#60;/tt&#62; if the attribute to be read is * @param labels the labels of the method's code, or &#60;tt&#62;null&#60;/tt&#62; if the attribute to be read is
* not a code attribute. * not a code attribute.
* @return a <i>new</i> {@link Attribute} object corresponding to the given bytes. * @return a <i>new</i> {@link Attribute} object corresponding to the given bytes.
*/ */
protected Attribute read( protected Attribute read(
final ClassReader cr, final ClassReader cr,
final int off, final int off,
final int len, final int len,
final char[] buf, final char[] buf,
final int codeOff, final int codeOff,
final Label[] labels) { final Label[] labels) {
Attribute attr = new Attribute(type); Attribute attr = new Attribute(type);
attr.value = new byte[len]; attr.value = new byte[len];
System.arraycopy(cr.b, off, attr.value, 0, len); System.arraycopy(cr.b, off, attr.value, 0, len);
return attr; return attr;
} }
/** /**
* Returns the byte array form of this attribute. * Returns the byte array form of this attribute.
* *
* @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool * @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool
* of this class the items that corresponds to this attribute. * of this class the items that corresponds to this attribute.
* @param code the bytecode of the method corresponding to this code attribute, or &#60;tt&#62;null&#60;/tt&#62; if * @param code the bytecode of the method corresponding to this code attribute, or &#60;tt&#62;null&#60;/tt&#62; if
* this attribute is not a code attributes. * this attribute is not a code attributes.
* @param len the length of the bytecode of the method corresponding to this code attribute, or * @param len the length of the bytecode of the method corresponding to this code attribute, or
* &#60;tt&#62;null&#60;/tt&#62; if this attribute is not a code attribute. * &#60;tt&#62;null&#60;/tt&#62; if this attribute is not a code attribute.
* @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this * @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this
* attribute is not a code attribute. * attribute is not a code attribute.
* @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1 * @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1
* if this attribute is not a code attribute. * if this attribute is not a code attribute.
* @return the byte array form of this attribute. * @return the byte array form of this attribute.
*/ */
protected ByteVector write( protected ByteVector write(
final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
ByteVector v = new ByteVector(); ByteVector v = new ByteVector();
v.data = value; v.data = value;
v.length = value.length; v.length = value.length;
return v; return v;
} }
/** /**
* Returns the length of the attribute list that begins with this attribute. * Returns the length of the attribute list that begins with this attribute.
* *
* @return the length of the attribute list that begins with this attribute. * @return the length of the attribute list that begins with this attribute.
*/ */
final int getCount() { final int getCount() {
int count = 0; int count = 0;
Attribute attr = this; Attribute attr = this;
while (attr != null) { while (attr != null) {
count += 1; count += 1;
attr = attr.next; attr = attr.next;
} }
return count; return count;
} }
/** /**
* Returns the size of all the attributes in this attribute list. * Returns the size of all the attributes in this attribute list.
* *
* @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write} * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
* method. * method.
* @param code the bytecode of the method corresponding to these code attributes, or &#60;tt&#62;null&#60;/tt&#62; * @param code the bytecode of the method corresponding to these code attributes, or &#60;tt&#62;null&#60;/tt&#62;
* if these attributes are not code attributes. * if these attributes are not code attributes.
* @param len the length of the bytecode of the method corresponding to these code attributes, or * @param len the length of the bytecode of the method corresponding to these code attributes, or
* &#60;tt&#62;null&#60;/tt&#62; if these attributes are not code attributes. * &#60;tt&#62;null&#60;/tt&#62; if these attributes are not code attributes.
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
* attributes are not code attributes. * attributes are not code attributes.
* @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
* -1 if these attributes are not code attributes. * -1 if these attributes are not code attributes.
* @return the size of all the attributes in this attribute list. This size includes the size of the attribute * @return the size of all the attributes in this attribute list. This size includes the size of the attribute
* headers. * headers.
*/ */
final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) { final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
Attribute attr = this; Attribute attr = this;
int size = 0; int size = 0;
while (attr != null) { while (attr != null) {
cw.newUTF8(attr.type); cw.newUTF8(attr.type);
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
attr = attr.next; attr = attr.next;
} }
return size; return size;
} }
/** /**
* Writes all the attributes of this attribute list in the given byte vector. * Writes all the attributes of this attribute list in the given byte vector.
* *
* @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write} * @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
* method. * method.
* @param code the bytecode of the method corresponding to these code attributes, or &#60;tt&#62;null&#60;/tt&#62; * @param code the bytecode of the method corresponding to these code attributes, or &#60;tt&#62;null&#60;/tt&#62;
* if these attributes are not code attributes. * if these attributes are not code attributes.
* @param len the length of the bytecode of the method corresponding to these code attributes, or * @param len the length of the bytecode of the method corresponding to these code attributes, or
* &#60;tt&#62;null&#60;/tt&#62; if these attributes are not code attributes. * &#60;tt&#62;null&#60;/tt&#62; if these attributes are not code attributes.
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these * @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
* attributes are not code attributes. * attributes are not code attributes.
* @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or * @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
* -1 if these attributes are not code attributes. * -1 if these attributes are not code attributes.
* @param out where the attributes must be written. * @param out where the attributes must be written.
*/ */
final void put( final void put(
final ClassWriter cw, final ClassWriter cw,
final byte[] code, final byte[] code,
final int len, final int len,
final int maxStack, final int maxStack,
final int maxLocals, final int maxLocals,
final ByteVector out) { final ByteVector out) {
Attribute attr = this; Attribute attr = this;
while (attr != null) { while (attr != null) {
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
out.putShort(cw.newUTF8(attr.type)).putInt(b.length); out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
out.putByteArray(b.data, 0, b.length); out.putByteArray(b.data, 0, b.length);
attr = attr.next; attr = attr.next;
} }
} }
// The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely // The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely
// removed. // removed.
// see also changes in ClassReader.accept. // see also changes in ClassReader.accept.
/** */ /** */
public static class NestMembers extends Attribute { public static class NestMembers extends Attribute {
/** */ /** */
public NestMembers() { public NestMembers() {
super("NestMembers"); super("NestMembers");
} }
byte[] bytes; byte[] bytes;
String[] classes; String[] classes;
@Override @Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
int offset = off; int offset = off;
NestMembers a = new NestMembers(); NestMembers a = new NestMembers();
int size = cr.readShort(off); int size = cr.readShort(off);
a.classes = new String[size]; a.classes = new String[size];
off += 2; off += 2;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
a.classes[i] = cr.readClass(off, buf); a.classes[i] = cr.readClass(off, buf);
off += 2; off += 2;
} }
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len); a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
return a; return a;
} }
@Override @Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
ByteVector v = new ByteVector(bytes.length); ByteVector v = new ByteVector(bytes.length);
v.putShort(classes.length); v.putShort(classes.length);
for (String s : classes) { for (String s : classes) {
v.putShort(cw.newClass(s)); v.putShort(cw.newClass(s));
} }
return v; return v;
} }
} }
/** */ /** */
public static class NestHost extends Attribute { public static class NestHost extends Attribute {
byte[] bytes; byte[] bytes;
String clazz; String clazz;
/** */ /** */
public NestHost() { public NestHost() {
super("NestHost"); super("NestHost");
} }
@Override @Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
int offset = off; int offset = off;
NestHost a = new NestHost(); NestHost a = new NestHost();
a.clazz = cr.readClass(off, buf); a.clazz = cr.readClass(off, buf);
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len); a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
return a; return a;
} }
@Override @Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
ByteVector v = new ByteVector(bytes.length); ByteVector v = new ByteVector(bytes.length);
v.putShort(cw.newClass(clazz)); v.putShort(cw.newClass(clazz));
return v; return v;
} }
} }
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()}; static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()};
} }

View File

@@ -66,266 +66,266 @@ package org.redkale.asm;
*/ */
public class ByteVector { public class ByteVector {
/** The content of this vector. */ /** The content of this vector. */
byte[] data; byte[] data;
/** Actual number of bytes in this vector. */ /** Actual number of bytes in this vector. */
int length; int length;
/** Constructs a new {@link ByteVector ByteVector} with a default initial size. */ /** Constructs a new {@link ByteVector ByteVector} with a default initial size. */
public ByteVector() { public ByteVector() {
data = new byte[64]; data = new byte[64];
} }
/** /**
* Constructs a new {@link ByteVector ByteVector} with the given initial size. * Constructs a new {@link ByteVector ByteVector} with the given initial size.
* *
* @param initialSize the initial size of the byte vector to be constructed. * @param initialSize the initial size of the byte vector to be constructed.
*/ */
public ByteVector(final int initialSize) { public ByteVector(final int initialSize) {
data = new byte[initialSize]; data = new byte[initialSize];
} }
/** /**
* Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary. * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param b a byte. * @param b a byte.
* @return this byte vector. * @return this byte vector.
*/ */
public ByteVector putByte(final int b) { public ByteVector putByte(final int b) {
int length = this.length; int length = this.length;
if (length + 1 > data.length) { if (length + 1 > data.length) {
enlarge(1); enlarge(1);
} }
data[length++] = (byte) b; data[length++] = (byte) b;
this.length = length; this.length = length;
return this; return this;
} }
/** /**
* Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary. * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param b1 a byte. * @param b1 a byte.
* @param b2 another byte. * @param b2 another byte.
* @return this byte vector. * @return this byte vector.
*/ */
ByteVector put11(final int b1, final int b2) { ByteVector put11(final int b1, final int b2) {
int length = this.length; int length = this.length;
if (length + 2 > data.length) { if (length + 2 > data.length) {
enlarge(2); enlarge(2);
} }
byte[] data = this.data; byte[] data = this.data;
data[length++] = (byte) b1; data[length++] = (byte) b1;
data[length++] = (byte) b2; data[length++] = (byte) b2;
this.length = length; this.length = length;
return this; return this;
} }
/** /**
* Puts a short into this byte vector. The byte vector is automatically enlarged if necessary. * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param s a short. * @param s a short.
* @return this byte vector. * @return this byte vector.
*/ */
public ByteVector putShort(final int s) { public ByteVector putShort(final int s) {
int length = this.length; int length = this.length;
if (length + 2 > data.length) { if (length + 2 > data.length) {
enlarge(2); enlarge(2);
} }
byte[] data = this.data; byte[] data = this.data;
data[length++] = (byte) (s >>> 8); data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s; data[length++] = (byte) s;
this.length = length; this.length = length;
return this; return this;
} }
/** /**
* Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary. * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param b a byte. * @param b a byte.
* @param s a short. * @param s a short.
* @return this byte vector. * @return this byte vector.
*/ */
ByteVector put12(final int b, final int s) { ByteVector put12(final int b, final int s) {
int length = this.length; int length = this.length;
if (length + 3 > data.length) { if (length + 3 > data.length) {
enlarge(3); enlarge(3);
} }
byte[] data = this.data; byte[] data = this.data;
data[length++] = (byte) b; data[length++] = (byte) b;
data[length++] = (byte) (s >>> 8); data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s; data[length++] = (byte) s;
this.length = length; this.length = length;
return this; return this;
} }
/** /**
* Puts an int into this byte vector. The byte vector is automatically enlarged if necessary. * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param i an int. * @param i an int.
* @return this byte vector. * @return this byte vector.
*/ */
public ByteVector putInt(final int i) { public ByteVector putInt(final int i) {
int length = this.length; int length = this.length;
if (length + 4 > data.length) { if (length + 4 > data.length) {
enlarge(4); enlarge(4);
} }
byte[] data = this.data; byte[] data = this.data;
data[length++] = (byte) (i >>> 24); data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16); data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8); data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i; data[length++] = (byte) i;
this.length = length; this.length = length;
return this; return this;
} }
/** /**
* Puts a long into this byte vector. The byte vector is automatically enlarged if necessary. * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param l a long. * @param l a long.
* @return this byte vector. * @return this byte vector.
*/ */
public ByteVector putLong(final long l) { public ByteVector putLong(final long l) {
int length = this.length; int length = this.length;
if (length + 8 > data.length) { if (length + 8 > data.length) {
enlarge(8); enlarge(8);
} }
byte[] data = this.data; byte[] data = this.data;
int i = (int) (l >>> 32); int i = (int) (l >>> 32);
data[length++] = (byte) (i >>> 24); data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16); data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8); data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i; data[length++] = (byte) i;
i = (int) l; i = (int) l;
data[length++] = (byte) (i >>> 24); data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16); data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8); data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i; data[length++] = (byte) i;
this.length = length; this.length = length;
return this; return this;
} }
/** /**
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param s a String whose UTF8 encoded length must be less than 65536. * @param s a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector. * @return this byte vector.
*/ */
public ByteVector putUTF8(final String s) { public ByteVector putUTF8(final String s) {
int charLength = s.length(); int charLength = s.length();
if (charLength > 65535) { if (charLength > 65535) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
int len = length; int len = length;
if (len + 2 + charLength > data.length) { if (len + 2 + charLength > data.length) {
enlarge(2 + charLength); enlarge(2 + charLength);
} }
byte[] data = this.data; byte[] data = this.data;
// optimistic algorithm: instead of computing the byte length and then // optimistic algorithm: instead of computing the byte length and then
// serializing the string (which requires two loops), we assume the byte // serializing the string (which requires two loops), we assume the byte
// length is equal to char length (which is the most frequent case), and // length is equal to char length (which is the most frequent case), and
// we start serializing the string right away. During the serialization, // we start serializing the string right away. During the serialization,
// if we find that this assumption is wrong, we continue with the // if we find that this assumption is wrong, we continue with the
// general method. // general method.
data[len++] = (byte) (charLength >>> 8); data[len++] = (byte) (charLength >>> 8);
data[len++] = (byte) charLength; data[len++] = (byte) charLength;
for (int i = 0; i < charLength; ++i) { for (int i = 0; i < charLength; ++i) {
char c = s.charAt(i); char c = s.charAt(i);
if (c >= '\001' && c <= '\177') { if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c; data[len++] = (byte) c;
} else { } else {
length = len; length = len;
return encodeUTF8(s, i, 65535); return encodeUTF8(s, i, 65535);
} }
} }
length = len; length = len;
return this; return this;
} }
/** /**
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string
* length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i * length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i
* - 2 >= 0). * - 2 >= 0).
* *
* @param s the String to encode. * @param s the String to encode.
* @param i the index of the first character to encode. The previous characters are supposed to have already been * @param i the index of the first character to encode. The previous characters are supposed to have already been
* encoded, using only one byte per character. * encoded, using only one byte per character.
* @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters. * @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters.
* @return this byte vector. * @return this byte vector.
*/ */
ByteVector encodeUTF8(final String s, int i, int maxByteLength) { ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
int charLength = s.length(); int charLength = s.length();
int byteLength = i; int byteLength = i;
char c; char c;
for (int j = i; j < charLength; ++j) { for (int j = i; j < charLength; ++j) {
c = s.charAt(j); c = s.charAt(j);
if (c >= '\001' && c <= '\177') { if (c >= '\001' && c <= '\177') {
byteLength++; byteLength++;
} else if (c > '\u07FF') { } else if (c > '\u07FF') {
byteLength += 3; byteLength += 3;
} else { } else {
byteLength += 2; byteLength += 2;
} }
} }
if (byteLength > maxByteLength) { if (byteLength > maxByteLength) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
int start = length - i - 2; int start = length - i - 2;
if (start >= 0) { if (start >= 0) {
data[start] = (byte) (byteLength >>> 8); data[start] = (byte) (byteLength >>> 8);
data[start + 1] = (byte) byteLength; data[start + 1] = (byte) byteLength;
} }
if (length + byteLength - i > data.length) { if (length + byteLength - i > data.length) {
enlarge(byteLength - i); enlarge(byteLength - i);
} }
int len = length; int len = length;
for (int j = i; j < charLength; ++j) { for (int j = i; j < charLength; ++j) {
c = s.charAt(j); c = s.charAt(j);
if (c >= '\001' && c <= '\177') { if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c; data[len++] = (byte) c;
} else if (c > '\u07FF') { } else if (c > '\u07FF') {
data[len++] = (byte) (0xE0 | c >> 12 & 0xF); data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
data[len++] = (byte) (0x80 | c >> 6 & 0x3F); data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
data[len++] = (byte) (0x80 | c & 0x3F); data[len++] = (byte) (0x80 | c & 0x3F);
} else { } else {
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
data[len++] = (byte) (0x80 | c & 0x3F); data[len++] = (byte) (0x80 | c & 0x3F);
} }
} }
length = len; length = len;
return this; return this;
} }
/** /**
* Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary. * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary.
* *
* @param b an array of bytes. May be &#60;tt&#62;null&#60;/tt&#62; to put &#60;tt&#62;len&#60;/tt&#62; null bytes * @param b an array of bytes. May be &#60;tt&#62;null&#60;/tt&#62; to put &#60;tt&#62;len&#60;/tt&#62; null bytes
* into this byte vector. * into this byte vector.
* @param off index of the fist byte of b that must be copied. * @param off index of the fist byte of b that must be copied.
* @param len number of bytes of b that must be copied. * @param len number of bytes of b that must be copied.
* @return this byte vector. * @return this byte vector.
*/ */
public ByteVector putByteArray(final byte[] b, final int off, final int len) { public ByteVector putByteArray(final byte[] b, final int off, final int len) {
if (length + len > data.length) { if (length + len > data.length) {
enlarge(len); enlarge(len);
} }
if (b != null) { if (b != null) {
System.arraycopy(b, off, data, length, len); System.arraycopy(b, off, data, length, len);
} }
length += len; length += len;
return this; return this;
} }
/** /**
* Enlarge this byte vector so that it can receive n more bytes. * Enlarge this byte vector so that it can receive n more bytes.
* *
* @param size number of additional bytes that this byte vector should be able to receive. * @param size number of additional bytes that this byte vector should be able to receive.
*/ */
private void enlarge(final int size) { private void enlarge(final int size) {
int length1 = 2 * data.length; int length1 = 2 * data.length;
int length2 = length + size; int length2 = length + size;
byte[] newData = new byte[length1 > length2 ? length1 : length2]; byte[] newData = new byte[length1 > length2 ? length1 : length2];
System.arraycopy(data, 0, newData, 0, length); System.arraycopy(data, 0, newData, 0, length);
data = newData; data = newData;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -70,223 +70,223 @@ package org.redkale.asm;
*/ */
public abstract class ClassVisitor { public abstract class ClassVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
protected final int api; protected final int api;
/** The class visitor to which this visitor must delegate method calls. May be null. */ /** The class visitor to which this visitor must delegate method calls. May be null. */
protected ClassVisitor cv; protected ClassVisitor cv;
/** /**
* Constructs a new {@link ClassVisitor}. * Constructs a new {@link ClassVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
public ClassVisitor(final int api) { public ClassVisitor(final int api) {
this(api, null); this(api, null);
} }
/** /**
* Constructs a new {@link ClassVisitor}. * Constructs a new {@link ClassVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param cv the class visitor to which this visitor must delegate method calls. May be null. * @param cv the class visitor to which this visitor must delegate method calls. May be null.
*/ */
public ClassVisitor(final int api, final ClassVisitor cv) { public ClassVisitor(final int api, final ClassVisitor cv) {
this.api = api; this.api = api;
this.cv = cv; this.cv = cv;
} }
/** /**
* Visits the header of the class. * Visits the header of the class.
* *
* @param version the class version. * @param version the class version.
* @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if the class is * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if the class is
* deprecated. * deprecated.
* @param name the internal name of the class (see {@link Type#getInternalName() getInternalName}). * @param name the internal name of the class (see {@link Type#getInternalName() getInternalName}).
* @param signature the signature of this class. May be &#60;tt&#62;null&#60;/tt&#62; if the class is not a generic * @param signature the signature of this class. May be &#60;tt&#62;null&#60;/tt&#62; if the class is not a generic
* one, and does not extend or implement generic classes or interfaces. * one, and does not extend or implement generic classes or interfaces.
* @param superName the internal of name of the super class (see {@link Type#getInternalName() getInternalName}). * @param superName the internal of name of the super class (see {@link Type#getInternalName() getInternalName}).
* For interfaces, the super class is {@link Object}. May be &#60;tt&#62;null&#60;/tt&#62;, but only for the * For interfaces, the super class is {@link Object}. May be &#60;tt&#62;null&#60;/tt&#62;, but only for the
* {@link Object} class. * {@link Object} class.
* @param interfaces the internal names of the class's interfaces (see {@link Type#getInternalName() * @param interfaces the internal names of the class's interfaces (see {@link Type#getInternalName()
* getInternalName}). May be &#60;tt&#62;null&#60;/tt&#62;. * getInternalName}). May be &#60;tt&#62;null&#60;/tt&#62;.
*/ */
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if (cv != null) { if (cv != null) {
cv.visit(version, access, name, signature, superName, interfaces); cv.visit(version, access, name, signature, superName, interfaces);
} }
} }
/** /**
* Visits the source of the class. * Visits the source of the class.
* *
* @param source the name of the source file from which the class was compiled. May be * @param source the name of the source file from which the class was compiled. May be
* &#60;tt&#62;null&#60;/tt&#62;. * &#60;tt&#62;null&#60;/tt&#62;.
* @param debug additional debug information to compute the correspondance between source and compiled elements of * @param debug additional debug information to compute the correspondance between source and compiled elements of
* the class. May be &#60;tt&#62;null&#60;/tt&#62;. * the class. May be &#60;tt&#62;null&#60;/tt&#62;.
*/ */
public void visitSource(String source, String debug) { public void visitSource(String source, String debug) {
if (cv != null) { if (cv != null) {
cv.visitSource(source, debug); cv.visitSource(source, debug);
} }
} }
/** /**
* Visit the module corresponding to the class. * Visit the module corresponding to the class.
* *
* @param name module name * @param name module name
* @param access module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. * @param access module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* @param version module version or null. * @param version module version or null.
* @return a visitor to visit the module values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not interested * @return a visitor to visit the module values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not interested
* in visiting this module. * in visiting this module.
*/ */
public ModuleVisitor visitModule(String name, int access, String version) { public ModuleVisitor visitModule(String name, int access, String version) {
if (api < Opcodes.ASM6) { if (api < Opcodes.ASM6) {
throw new RuntimeException(); throw new RuntimeException();
} }
if (cv != null) { if (cv != null) {
return cv.visitModule(name, access, version); return cv.visitModule(name, access, version);
} }
return null; return null;
} }
/** /**
* Visits the enclosing class of the class. This method must be called only if the class has an enclosing class. * Visits the enclosing class of the class. This method must be called only if the class has an enclosing class.
* *
* @param owner internal name of the enclosing class of the class. * @param owner internal name of the enclosing class of the class.
* @param name the name of the method that contains the class, or &#60;tt&#62;null&#60;/tt&#62; if the class is not * @param name the name of the method that contains the class, or &#60;tt&#62;null&#60;/tt&#62; if the class is not
* enclosed in a method of its enclosing class. * enclosed in a method of its enclosing class.
* @param desc the descriptor of the method that contains the class, or &#60;tt&#62;null&#60;/tt&#62; if the class * @param desc the descriptor of the method that contains the class, or &#60;tt&#62;null&#60;/tt&#62; if the class
* is not enclosed in a method of its enclosing class. * is not enclosed in a method of its enclosing class.
*/ */
public void visitOuterClass(String owner, String name, String desc) { public void visitOuterClass(String owner, String name, String desc) {
if (cv != null) { if (cv != null) {
cv.visitOuterClass(owner, name, desc); cv.visitOuterClass(owner, name, desc);
} }
} }
/** /**
* Visits an annotation of the class. * Visits an annotation of the class.
* *
* @param desc the class descriptor of the annotation class. * @param desc the class descriptor of the annotation class.
* @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime. * @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not * @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not
* interested in visiting this annotation. * interested in visiting this annotation.
*/ */
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (cv != null) { if (cv != null) {
return cv.visitAnnotation(desc, visible); return cv.visitAnnotation(desc, visible);
} }
return null; return null;
} }
/** /**
* Visits an annotation on a type in the class signature. * Visits an annotation on a type in the class signature.
* *
* @param typeRef a reference to the annotated type. The sort of this type reference must be * @param typeRef a reference to the annotated type. The sort of this type reference must be
* {@link TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, * {@link TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See {@link TypeReference}. * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See {@link TypeReference}.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
* within 'typeRef'. May be &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole. * within 'typeRef'. May be &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param desc the class descriptor of the annotation class. * @param desc the class descriptor of the annotation class.
* @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime. * @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not * @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not
* interested in visiting this annotation. * interested in visiting this annotation.
*/ */
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
if (cv != null) { if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
} }
return null; return null;
} }
/** /**
* Visits a non standard attribute of the class. * Visits a non standard attribute of the class.
* *
* @param attr an attribute. * @param attr an attribute.
*/ */
public void visitAttribute(Attribute attr) { public void visitAttribute(Attribute attr) {
if (cv != null) { if (cv != null) {
cv.visitAttribute(attr); cv.visitAttribute(attr);
} }
} }
/** /**
* Visits information about an inner class. This inner class is not necessarily a member of the class being visited. * Visits information about an inner class. This inner class is not necessarily a member of the class being visited.
* *
* @param name the internal name of an inner class (see {@link Type#getInternalName() getInternalName}). * @param name the internal name of an inner class (see {@link Type#getInternalName() getInternalName}).
* @param outerName the internal name of the class to which the inner class belongs (see * @param outerName the internal name of the class to which the inner class belongs (see
* {@link Type#getInternalName() getInternalName}). May be &#60;tt&#62;null&#60;/tt&#62; for not member classes. * {@link Type#getInternalName() getInternalName}). May be &#60;tt&#62;null&#60;/tt&#62; for not member classes.
* @param innerName the (simple) name of the inner class inside its enclosing class. May be * @param innerName the (simple) name of the inner class inside its enclosing class. May be
* &#60;tt&#62;null&#60;/tt&#62; for anonymous inner classes. * &#60;tt&#62;null&#60;/tt&#62; for anonymous inner classes.
* @param access the access flags of the inner class as originally declared in the enclosing class. * @param access the access flags of the inner class as originally declared in the enclosing class.
*/ */
public void visitInnerClass(String name, String outerName, String innerName, int access) { public void visitInnerClass(String name, String outerName, String innerName, int access) {
if (cv != null) { if (cv != null) {
cv.visitInnerClass(name, outerName, innerName, access); cv.visitInnerClass(name, outerName, innerName, access);
} }
} }
/** /**
* Visits a field of the class. * Visits a field of the class.
* *
* @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if the field is * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if the field is
* synthetic and/or deprecated. * synthetic and/or deprecated.
* @param name the field's name. * @param name the field's name.
* @param desc the field's descriptor (see {@link Type Type}). * @param desc the field's descriptor (see {@link Type Type}).
* @param signature the field's signature. May be &#60;tt&#62;null&#60;/tt&#62; if the field's type does not use * @param signature the field's signature. May be &#60;tt&#62;null&#60;/tt&#62; if the field's type does not use
* generic types. * generic types.
* @param value the field's initial value. This parameter, which may be &#60;tt&#62;null&#60;/tt&#62; if the field * @param value the field's initial value. This parameter, which may be &#60;tt&#62;null&#60;/tt&#62; if the field
* does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}
* or a {@link String} (for &#60;tt&#62;int&#60;/tt&#62;, &#60;tt&#62;float&#60;/tt&#62;, * or a {@link String} (for &#60;tt&#62;int&#60;/tt&#62;, &#60;tt&#62;float&#60;/tt&#62;,
* &#60;tt&#62;long&#60;/tt&#62; or &#60;tt&#62;String&#60;/tt&#62; fields respectively). <i>This parameter is * &#60;tt&#62;long&#60;/tt&#62; or &#60;tt&#62;String&#60;/tt&#62; fields respectively). <i>This parameter is
* only used for static fields</i>. Its value is ignored for non static fields, which must be initialized * only used for static fields</i>. Its value is ignored for non static fields, which must be initialized
* through bytecode instructions in constructors or methods. * through bytecode instructions in constructors or methods.
* @return a visitor to visit field annotations and attributes, or &#60;tt&#62;null&#60;/tt&#62; if this class * @return a visitor to visit field annotations and attributes, or &#60;tt&#62;null&#60;/tt&#62; if this class
* visitor is not interested in visiting these annotations and attributes. * visitor is not interested in visiting these annotations and attributes.
*/ */
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
if (cv != null) { if (cv != null) {
return cv.visitField(access, name, desc, signature, value); return cv.visitField(access, name, desc, signature, value);
} }
return null; return null;
} }
/** /**
* Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor} instance (or * Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor} instance (or
* &#60;tt&#62;null&#60;/tt&#62;) each time it is called, i.e., it should not return a previously returned visitor. * &#60;tt&#62;null&#60;/tt&#62;) each time it is called, i.e., it should not return a previously returned visitor.
* *
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if the method is * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if the method is
* synthetic and/or deprecated. * synthetic and/or deprecated.
* @param name the method's name. * @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}). * @param desc the method's descriptor (see {@link Type Type}).
* @param signature the method's signature. May be &#60;tt&#62;null&#60;/tt&#62; if the method parameters, return * @param signature the method's signature. May be &#60;tt&#62;null&#60;/tt&#62; if the method parameters, return
* type and exceptions do not use generic types. * type and exceptions do not use generic types.
* @param exceptions the internal names of the method's exception classes (see {@link Type#getInternalName() * @param exceptions the internal names of the method's exception classes (see {@link Type#getInternalName()
* getInternalName}). May be &#60;tt&#62;null&#60;/tt&#62;. * getInternalName}). May be &#60;tt&#62;null&#60;/tt&#62;.
* @return an object to visit the byte code of the method, or &#60;tt&#62;null&#60;/tt&#62; if this class visitor is * @return an object to visit the byte code of the method, or &#60;tt&#62;null&#60;/tt&#62; if this class visitor is
* not interested in visiting the code of this method. * not interested in visiting the code of this method.
*/ */
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (cv != null) { if (cv != null) {
return cv.visitMethod(access, name, desc, signature, exceptions); return cv.visitMethod(access, name, desc, signature, exceptions);
} }
return null; return null;
} }
/** /**
* Visits the end of the class. This method, which is the last one to be called, is used to inform the visitor that * Visits the end of the class. This method, which is the last one to be called, is used to inform the visitor that
* all the fields and methods of the class have been visited. * all the fields and methods of the class have been visited.
*/ */
public void visitEnd() { public void visitEnd() {
if (cv != null) { if (cv != null) {
cv.visitEnd(); cv.visitEnd();
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -66,78 +66,78 @@ package org.redkale.asm;
*/ */
class Context { class Context {
/** Prototypes of the attributes that must be parsed for this class. */ /** Prototypes of the attributes that must be parsed for this class. */
Attribute[] attrs; Attribute[] attrs;
/** The {@link ClassReader} option flags for the parsing of this class. */ /** The {@link ClassReader} option flags for the parsing of this class. */
int flags; int flags;
/** The buffer used to read strings. */ /** The buffer used to read strings. */
char[] buffer; char[] buffer;
/** The start index of each bootstrap method. */ /** The start index of each bootstrap method. */
int[] bootstrapMethods; int[] bootstrapMethods;
/** The access flags of the method currently being parsed. */ /** The access flags of the method currently being parsed. */
int access; int access;
/** The name of the method currently being parsed. */ /** The name of the method currently being parsed. */
String name; String name;
/** The descriptor of the method currently being parsed. */ /** The descriptor of the method currently being parsed. */
String desc; String desc;
/** /**
* The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for * The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for
* which a label is needed have a non null associated Label object). * which a label is needed have a non null associated Label object).
*/ */
Label[] labels; Label[] labels;
/** The target of the type annotation currently being parsed. */ /** The target of the type annotation currently being parsed. */
int typeRef; int typeRef;
/** The path of the type annotation currently being parsed. */ /** The path of the type annotation currently being parsed. */
TypePath typePath; TypePath typePath;
/** The offset of the latest stack map frame that has been parsed. */ /** The offset of the latest stack map frame that has been parsed. */
int offset; int offset;
/** /**
* The labels corresponding to the start of the local variable ranges in the local variable type annotation * The labels corresponding to the start of the local variable ranges in the local variable type annotation
* currently being parsed. * currently being parsed.
*/ */
Label[] start; Label[] start;
/** /**
* The labels corresponding to the end of the local variable ranges in the local variable type annotation currently * The labels corresponding to the end of the local variable ranges in the local variable type annotation currently
* being parsed. * being parsed.
*/ */
Label[] end; Label[] end;
/** /**
* The local variable indices for each local variable range in the local variable type annotation currently being * The local variable indices for each local variable range in the local variable type annotation currently being
* parsed. * parsed.
*/ */
int[] index; int[] index;
/** The encoding of the latest stack map frame that has been parsed. */ /** The encoding of the latest stack map frame that has been parsed. */
int mode; int mode;
/** The number of locals in the latest stack map frame that has been parsed. */ /** The number of locals in the latest stack map frame that has been parsed. */
int localCount; int localCount;
/** /**
* The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous * The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous
* frame. * frame.
*/ */
int localDiff; int localDiff;
/** The local values of the latest stack map frame that has been parsed. */ /** The local values of the latest stack map frame that has been parsed. */
Object[] local; Object[] local;
/** The stack size of the latest stack map frame that has been parsed. */ /** The stack size of the latest stack map frame that has been parsed. */
int stackCount; int stackCount;
/** The stack values of the latest stack map frame that has been parsed. */ /** The stack values of the latest stack map frame that has been parsed. */
Object[] stack; Object[] stack;
} }

View File

@@ -67,17 +67,17 @@ package org.redkale.asm;
*/ */
class CurrentFrame extends Frame { class CurrentFrame extends Frame {
/** /**
* Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the instruction just * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the instruction just
* after the given one. It is assumed that the value of this object when this method is called is the stack map * after the given one. It is assumed that the value of this object when this method is called is the stack map
* frame status just before the given instruction is executed. * frame status just before the given instruction is executed.
*/ */
@Override @Override
void execute(int opcode, int arg, ClassWriter cw, Item item) { void execute(int opcode, int arg, ClassWriter cw, Item item) {
super.execute(opcode, arg, cw, item); super.execute(opcode, arg, cw, item);
Frame successor = new Frame(); Frame successor = new Frame();
merge(cw, successor, 0); merge(cw, successor, 0);
set(successor); set(successor);
owner.inputStackTop = 0; owner.inputStackTop = 0;
} }
} }

View File

@@ -65,30 +65,30 @@ package org.redkale.asm;
*/ */
class Edge { class Edge {
/** Denotes a normal control flow graph edge. */ /** Denotes a normal control flow graph edge. */
static final int NORMAL = 0; static final int NORMAL = 0;
/** /**
* Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose * Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose
* {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the * {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the
* index, in the {@link ClassWriter} type table, of the exception that is catched. * index, in the {@link ClassWriter} type table, of the exception that is catched.
*/ */
static final int EXCEPTION = 0x7FFFFFFF; static final int EXCEPTION = 0x7FFFFFFF;
/** /**
* Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the * Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the
* (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at * (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at
* the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the * the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control
* flow graph edge (i.e. NORMAL or EXCEPTION). * flow graph edge (i.e. NORMAL or EXCEPTION).
*/ */
int info; int info;
/** The successor block of the basic block from which this edge originates. */ /** The successor block of the basic block from which this edge originates. */
Label successor; Label successor;
/** /**
* The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}. * The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}.
*/ */
Edge next; Edge next;
} }

View File

@@ -67,89 +67,89 @@ package org.redkale.asm;
*/ */
public abstract class FieldVisitor { public abstract class FieldVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4}, * The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
protected final int api; protected final int api;
/** The field visitor to which this visitor must delegate method calls. May be null. */ /** The field visitor to which this visitor must delegate method calls. May be null. */
protected FieldVisitor fv; protected FieldVisitor fv;
/** /**
* Constructs a new {@link FieldVisitor}. * Constructs a new {@link FieldVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
public FieldVisitor(final int api) { public FieldVisitor(final int api) {
this(api, null); this(api, null);
} }
/** /**
* Constructs a new {@link FieldVisitor}. * Constructs a new {@link FieldVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}, * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param fv the field visitor to which this visitor must delegate method calls. May be null. * @param fv the field visitor to which this visitor must delegate method calls. May be null.
*/ */
public FieldVisitor(final int api, final FieldVisitor fv) { public FieldVisitor(final int api, final FieldVisitor fv) {
this.api = api; this.api = api;
this.fv = fv; this.fv = fv;
} }
/** /**
* Visits an annotation of the field. * Visits an annotation of the field.
* *
* @param desc the class descriptor of the annotation class. * @param desc the class descriptor of the annotation class.
* @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime. * @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not * @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not
* interested in visiting this annotation. * interested in visiting this annotation.
*/ */
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (fv != null) { if (fv != null) {
return fv.visitAnnotation(desc, visible); return fv.visitAnnotation(desc, visible);
} }
return null; return null;
} }
/** /**
* Visits an annotation on the type of the field. * Visits an annotation on the type of the field.
* *
* @param typeRef a reference to the annotated type. The sort of this type reference must be * @param typeRef a reference to the annotated type. The sort of this type reference must be
* {@link TypeReference#FIELD FIELD}. See {@link TypeReference}. * {@link TypeReference#FIELD FIELD}. See {@link TypeReference}.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type * @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
* within 'typeRef'. May be &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole. * within 'typeRef'. May be &#60;tt&#62;null&#60;/tt&#62; if the annotation targets 'typeRef' as a whole.
* @param desc the class descriptor of the annotation class. * @param desc the class descriptor of the annotation class.
* @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime. * @param visible &#60;tt&#62;true&#60;/tt&#62; if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not * @return a visitor to visit the annotation values, or &#60;tt&#62;null&#60;/tt&#62; if this visitor is not
* interested in visiting this annotation. * interested in visiting this annotation.
*/ */
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
if (fv != null) { if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible); return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
} }
return null; return null;
} }
/** /**
* Visits a non standard attribute of the field. * Visits a non standard attribute of the field.
* *
* @param attr an attribute. * @param attr an attribute.
*/ */
public void visitAttribute(Attribute attr) { public void visitAttribute(Attribute attr) {
if (fv != null) { if (fv != null) {
fv.visitAttribute(attr); fv.visitAttribute(attr);
} }
} }
/** /**
* Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that * Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that
* all the annotations and attributes of the field have been visited. * all the annotations and attributes of the field have been visited.
*/ */
public void visitEnd() { public void visitEnd() {
if (fv != null) { if (fv != null) {
fv.visitEnd(); fv.visitEnd();
} }
} }
} }

View File

@@ -65,256 +65,256 @@ package org.redkale.asm;
*/ */
final class FieldWriter extends FieldVisitor { final class FieldWriter extends FieldVisitor {
/** The class writer to which this field must be added. */ /** The class writer to which this field must be added. */
private final ClassWriter cw; private final ClassWriter cw;
/** Access flags of this field. */ /** Access flags of this field. */
private final int access; private final int access;
/** The index of the constant pool item that contains the name of this method. */ /** The index of the constant pool item that contains the name of this method. */
private final int name; private final int name;
/** The index of the constant pool item that contains the descriptor of this field. */ /** The index of the constant pool item that contains the descriptor of this field. */
private final int desc; private final int desc;
/** The index of the constant pool item that contains the signature of this field. */ /** The index of the constant pool item that contains the signature of this field. */
private int signature; private int signature;
/** The index of the constant pool item that contains the constant value of this field. */ /** The index of the constant pool item that contains the constant value of this field. */
private int value; private int value;
/** The runtime visible annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */ /** The runtime visible annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */
private AnnotationWriter anns; private AnnotationWriter anns;
/** The runtime invisible annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */ /** The runtime invisible annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */
private AnnotationWriter ianns; private AnnotationWriter ianns;
/** The runtime visible type annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */ /** The runtime visible type annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */
private AnnotationWriter tanns; private AnnotationWriter tanns;
/** The runtime invisible type annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */ /** The runtime invisible type annotations of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */
private AnnotationWriter itanns; private AnnotationWriter itanns;
/** The non standard attributes of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */ /** The non standard attributes of this field. May be &#60;tt&#62;null&#60;/tt&#62;. */
private Attribute attrs; private Attribute attrs;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Constructor // Constructor
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Constructs a new {@link FieldWriter}. * Constructs a new {@link FieldWriter}.
* *
* @param cw the class writer to which this field must be added. * @param cw the class writer to which this field must be added.
* @param access the field's access flags (see {@link Opcodes}). * @param access the field's access flags (see {@link Opcodes}).
* @param name the field's name. * @param name the field's name.
* @param desc the field's descriptor (see {@link Type}). * @param desc the field's descriptor (see {@link Type}).
* @param signature the field's signature. May be &#60;tt&#62;null&#60;/tt&#62;. * @param signature the field's signature. May be &#60;tt&#62;null&#60;/tt&#62;.
* @param value the field's constant value. May be &#60;tt&#62;null&#60;/tt&#62;. * @param value the field's constant value. May be &#60;tt&#62;null&#60;/tt&#62;.
*/ */
FieldWriter( FieldWriter(
final ClassWriter cw, final ClassWriter cw,
final int access, final int access,
final String name, final String name,
final String desc, final String desc,
final String signature, final String signature,
final Object value) { final Object value) {
super(Opcodes.ASM6); super(Opcodes.ASM6);
if (cw.firstField == null) { if (cw.firstField == null) {
cw.firstField = this; cw.firstField = this;
} else { } else {
cw.lastField.fv = this; cw.lastField.fv = this;
} }
cw.lastField = this; cw.lastField = this;
this.cw = cw; this.cw = cw;
this.access = access; this.access = access;
this.name = cw.newUTF8(name); this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc); this.desc = cw.newUTF8(desc);
if (signature != null) { if (signature != null) {
this.signature = cw.newUTF8(signature); this.signature = cw.newUTF8(signature);
} }
if (value != null) { if (value != null) {
this.value = cw.newConstItem(value).index; this.value = cw.newConstItem(value).index;
} }
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class // Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@Override @Override
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
ByteVector bv = new ByteVector(); ByteVector bv = new ByteVector();
// write type, and reserve space for values count // write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0); bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
if (visible) { if (visible) {
aw.next = anns; aw.next = anns;
anns = aw; anns = aw;
} else { } else {
aw.next = ianns; aw.next = ianns;
ianns = aw; ianns = aw;
} }
return aw; return aw;
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation( public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String desc, final boolean visible) { final int typeRef, final TypePath typePath, final String desc, final boolean visible) {
ByteVector bv = new ByteVector(); ByteVector bv = new ByteVector();
// write target_type and target_info // write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv); AnnotationWriter.putTarget(typeRef, typePath, bv);
// write type, and reserve space for values count // write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0); bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2); AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
if (visible) { if (visible) {
aw.next = tanns; aw.next = tanns;
tanns = aw; tanns = aw;
} else { } else {
aw.next = itanns; aw.next = itanns;
itanns = aw; itanns = aw;
} }
return aw; return aw;
} }
@Override @Override
public void visitAttribute(final Attribute attr) { public void visitAttribute(final Attribute attr) {
attr.next = attrs; attr.next = attrs;
attrs = attr; attrs = attr;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
// do nothing // do nothing
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Utility methods // Utility methods
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Returns the size of this field. * Returns the size of this field.
* *
* @return the size of this field. * @return the size of this field.
*/ */
int getSize() { int getSize() {
int size = 8; int size = 8;
if (value != 0) { if (value != 0) {
cw.newUTF8("ConstantValue"); cw.newUTF8("ConstantValue");
size += 8; size += 8;
} }
if ((access & Opcodes.ACC_SYNTHETIC) != 0) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
cw.newUTF8("Synthetic"); cw.newUTF8("Synthetic");
size += 6; size += 6;
} }
} }
if ((access & Opcodes.ACC_DEPRECATED) != 0) { if ((access & Opcodes.ACC_DEPRECATED) != 0) {
cw.newUTF8("Deprecated"); cw.newUTF8("Deprecated");
size += 6; size += 6;
} }
if (signature != 0) { if (signature != 0) {
cw.newUTF8("Signature"); cw.newUTF8("Signature");
size += 8; size += 8;
} }
if (anns != null) { if (anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations"); cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize(); size += 8 + anns.getSize();
} }
if (ianns != null) { if (ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations"); cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize(); size += 8 + ianns.getSize();
} }
if (tanns != null) { if (tanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations"); cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + tanns.getSize(); size += 8 + tanns.getSize();
} }
if (itanns != null) { if (itanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations"); cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + itanns.getSize(); size += 8 + itanns.getSize();
} }
if (attrs != null) { if (attrs != null) {
size += attrs.getSize(cw, null, 0, -1, -1); size += attrs.getSize(cw, null, 0, -1, -1);
} }
return size; return size;
} }
/** /**
* Puts the content of this field into the given byte vector. * Puts the content of this field into the given byte vector.
* *
* @param out where the content of this field must be put. * @param out where the content of this field must be put.
*/ */
void put(final ByteVector out) { void put(final ByteVector out) {
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
int mask = Opcodes.ACC_DEPRECATED int mask = Opcodes.ACC_DEPRECATED
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
out.putShort(access & ~mask).putShort(name).putShort(desc); out.putShort(access & ~mask).putShort(name).putShort(desc);
int attributeCount = 0; int attributeCount = 0;
if (value != 0) { if (value != 0) {
++attributeCount; ++attributeCount;
} }
if ((access & Opcodes.ACC_SYNTHETIC) != 0) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
++attributeCount; ++attributeCount;
} }
} }
if ((access & Opcodes.ACC_DEPRECATED) != 0) { if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount; ++attributeCount;
} }
if (signature != 0) { if (signature != 0) {
++attributeCount; ++attributeCount;
} }
if (anns != null) { if (anns != null) {
++attributeCount; ++attributeCount;
} }
if (ianns != null) { if (ianns != null) {
++attributeCount; ++attributeCount;
} }
if (tanns != null) { if (tanns != null) {
++attributeCount; ++attributeCount;
} }
if (itanns != null) { if (itanns != null) {
++attributeCount; ++attributeCount;
} }
if (attrs != null) { if (attrs != null) {
attributeCount += attrs.getCount(); attributeCount += attrs.getCount();
} }
out.putShort(attributeCount); out.putShort(attributeCount);
if (value != 0) { if (value != 0) {
out.putShort(cw.newUTF8("ConstantValue")); out.putShort(cw.newUTF8("ConstantValue"));
out.putInt(2).putShort(value); out.putInt(2).putShort(value);
} }
if ((access & Opcodes.ACC_SYNTHETIC) != 0) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
out.putShort(cw.newUTF8("Synthetic")).putInt(0); out.putShort(cw.newUTF8("Synthetic")).putInt(0);
} }
} }
if ((access & Opcodes.ACC_DEPRECATED) != 0) { if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0); out.putShort(cw.newUTF8("Deprecated")).putInt(0);
} }
if (signature != 0) { if (signature != 0) {
out.putShort(cw.newUTF8("Signature")); out.putShort(cw.newUTF8("Signature"));
out.putInt(2).putShort(signature); out.putInt(2).putShort(signature);
} }
if (anns != null) { if (anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out); anns.put(out);
} }
if (ianns != null) { if (ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out); ianns.put(out);
} }
if (tanns != null) { if (tanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out); tanns.put(out);
} }
if (itanns != null) { if (itanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out); itanns.put(out);
} }
if (attrs != null) { if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out); attrs.put(cw, null, 0, -1, -1, out);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -67,124 +67,124 @@ package org.redkale.asm;
*/ */
public final class Handle { public final class Handle {
/** /**
* The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD}, * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
*/ */
final int tag; final int tag;
/** The internal name of the class that owns the field or method designated by this handle. */ /** The internal name of the class that owns the field or method designated by this handle. */
final String owner; final String owner;
/** The name of the field or method designated by this handle. */ /** The name of the field or method designated by this handle. */
final String name; final String name;
/** The descriptor of the field or method designated by this handle. */ /** The descriptor of the field or method designated by this handle. */
final String desc; final String desc;
/** Indicate if the owner is an interface or not. */ /** Indicate if the owner is an interface or not. */
final boolean itf; final boolean itf;
/** /**
* Constructs a new field or method handle. * Constructs a new field or method handle.
* *
* @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD}, * @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD},
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the class that owns the field or method designated by this handle. * @param owner the internal name of the class that owns the field or method designated by this handle.
* @param name the name of the field or method designated by this handle. * @param name the name of the field or method designated by this handle.
* @param desc the descriptor of the field or method designated by this handle. * @param desc the descriptor of the field or method designated by this handle.
* @param itf true if the owner is an interface. * @param itf true if the owner is an interface.
*/ */
public Handle(int tag, String owner, String name, String desc, boolean itf) { public Handle(int tag, String owner, String name, String desc, boolean itf) {
this.tag = tag; this.tag = tag;
this.owner = owner; this.owner = owner;
this.name = name; this.name = name;
this.desc = desc; this.desc = desc;
this.itf = itf; this.itf = itf;
} }
/** /**
* Returns the kind of field or method designated by this handle. * Returns the kind of field or method designated by this handle.
* *
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
* {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
*/ */
public int getTag() { public int getTag() {
return tag; return tag;
} }
/** /**
* Returns the internal name of the class that owns the field or method designated by this handle. * Returns the internal name of the class that owns the field or method designated by this handle.
* *
* @return the internal name of the class that owns the field or method designated by this handle. * @return the internal name of the class that owns the field or method designated by this handle.
*/ */
public String getOwner() { public String getOwner() {
return owner; return owner;
} }
/** /**
* Returns the name of the field or method designated by this handle. * Returns the name of the field or method designated by this handle.
* *
* @return the name of the field or method designated by this handle. * @return the name of the field or method designated by this handle.
*/ */
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* Returns the descriptor of the field or method designated by this handle. * Returns the descriptor of the field or method designated by this handle.
* *
* @return the descriptor of the field or method designated by this handle. * @return the descriptor of the field or method designated by this handle.
*/ */
public String getDesc() { public String getDesc() {
return desc; return desc;
} }
/** /**
* Returns true if the owner of the field or method designated by this handle is an interface. * Returns true if the owner of the field or method designated by this handle is an interface.
* *
* @return true if the owner of the field or method designated by this handle is an interface. * @return true if the owner of the field or method designated by this handle is an interface.
*/ */
public boolean isInterface() { public boolean isInterface() {
return itf; return itf;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == this) { if (obj == this) {
return true; return true;
} }
if (!(obj instanceof Handle)) { if (!(obj instanceof Handle)) {
return false; return false;
} }
Handle h = (Handle) obj; Handle h = (Handle) obj;
return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc); return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode(); return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
} }
/** /**
* Returns the textual representation of this handle. The textual representation is: * Returns the textual representation of this handle. The textual representation is:
* *
* <pre> * <pre>
* for a reference to a class: * for a reference to a class:
* owner '.' name desc ' ' '(' tag ')' * owner '.' name desc ' ' '(' tag ')'
* for a reference to an interface: * for a reference to an interface:
* owner '.' name desc ' ' '(' tag ' ' itf ')' * owner '.' name desc ' ' '(' tag ' ' itf ')'
* </pre> * </pre>
* *
* . As this format is unambiguous, it can be parsed if necessary. * . As this format is unambiguous, it can be parsed if necessary.
*/ */
@Override @Override
public String toString() { public String toString() {
return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')'; return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')';
} }
} }

View File

@@ -65,74 +65,74 @@ package org.redkale.asm;
*/ */
class Handler { class Handler {
/** Beginning of the exception handler's scope (inclusive). */ /** Beginning of the exception handler's scope (inclusive). */
Label start; Label start;
/** End of the exception handler's scope (exclusive). */ /** End of the exception handler's scope (exclusive). */
Label end; Label end;
/** Beginning of the exception handler's code. */ /** Beginning of the exception handler's code. */
Label handler; Label handler;
/** /**
* Internal name of the type of exceptions handled by this handler, or &#60;tt&#62;null&#60;/tt&#62; to catch any * Internal name of the type of exceptions handled by this handler, or &#60;tt&#62;null&#60;/tt&#62; to catch any
* exceptions. * exceptions.
*/ */
String desc; String desc;
/** /**
* Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any * Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any
* exceptions. * exceptions.
*/ */
int type; int type;
/** Next exception handler block info. */ /** Next exception handler block info. */
Handler next; Handler next;
/** /**
* Removes the range between start and end from the given exception handlers. * Removes the range between start and end from the given exception handlers.
* *
* @param h an exception handler list. * @param h an exception handler list.
* @param start the start of the range to be removed. * @param start the start of the range to be removed.
* @param end the end of the range to be removed. Maybe null. * @param end the end of the range to be removed. Maybe null.
* @return the exception handler list with the start-end range removed. * @return the exception handler list with the start-end range removed.
*/ */
static Handler remove(Handler h, Label start, Label end) { static Handler remove(Handler h, Label start, Label end) {
if (h == null) { if (h == null) {
return null; return null;
} else { } else {
h.next = remove(h.next, start, end); h.next = remove(h.next, start, end);
} }
int hstart = h.start.position; int hstart = h.start.position;
int hend = h.end.position; int hend = h.end.position;
int s = start.position; int s = start.position;
int e = end == null ? Integer.MAX_VALUE : end.position; int e = end == null ? Integer.MAX_VALUE : end.position;
// if [hstart,hend[ and [s,e[ intervals intersect... // if [hstart,hend[ and [s,e[ intervals intersect...
if (s < hend && e > hstart) { if (s < hend && e > hstart) {
if (s <= hstart) { if (s <= hstart) {
if (e >= hend) { if (e >= hend) {
// [hstart,hend[ fully included in [s,e[, h removed // [hstart,hend[ fully included in [s,e[, h removed
h = h.next; h = h.next;
} else { } else {
// [hstart,hend[ minus [s,e[ = [e,hend[ // [hstart,hend[ minus [s,e[ = [e,hend[
h.start = end; h.start = end;
} }
} else if (e >= hend) { } else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [hstart,s[ // [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start; h.end = start;
} else { } else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[ // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
Handler g = new Handler(); Handler g = new Handler();
g.start = end; g.start = end;
g.end = h.end; g.end = h.end;
g.handler = h.handler; g.handler = h.handler;
g.desc = h.desc; g.desc = h.desc;
g.type = h.type; g.type = h.type;
g.next = h.next; g.next = h.next;
h.end = start; h.end = start;
h.next = g; h.next = g;
} }
} }
return h; return h;
} }
} }

View File

@@ -65,225 +65,225 @@ package org.redkale.asm;
*/ */
final class Item { final class Item {
/** Index of this item in the constant pool. */ /** Index of this item in the constant pool. */
int index; int index;
/** /**
* Type of this constant pool item. A single class is used to represent all constant pool item types, in order to * Type of this constant pool item. A single class is used to represent all constant pool item types, in order to
* minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT}, * minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT},
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8}, * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE}, * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
* *
* <p>MethodHandle constant 9 variations are stored using a range of 9 values from {@link ClassWriter#HANDLE_BASE} + * <p>MethodHandle constant 9 variations are stored using a range of 9 values from {@link ClassWriter#HANDLE_BASE} +
* 1 to {@link ClassWriter#HANDLE_BASE} + 9. * 1 to {@link ClassWriter#HANDLE_BASE} + 9.
* *
* <p>Special Item types are used for Items that are stored in the ClassWriter {@link ClassWriter#typeTable}, * <p>Special Item types are used for Items that are stored in the ClassWriter {@link ClassWriter#typeTable},
* instead of the constant pool, in order to avoid clashes with normal constant pool items in the ClassWriter * instead of the constant pool, in order to avoid clashes with normal constant pool items in the ClassWriter
* constant pool's hash table. These special item types are {@link ClassWriter#TYPE_NORMAL}, * constant pool's hash table. These special item types are {@link ClassWriter#TYPE_NORMAL},
* {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}. * {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}.
*/ */
int type; int type;
/** Value of this item, for an integer item. */ /** Value of this item, for an integer item. */
int intVal; int intVal;
/** Value of this item, for a long item. */ /** Value of this item, for a long item. */
long longVal; long longVal;
/** First part of the value of this item, for items that do not hold a primitive value. */ /** First part of the value of this item, for items that do not hold a primitive value. */
String strVal1; String strVal1;
/** Second part of the value of this item, for items that do not hold a primitive value. */ /** Second part of the value of this item, for items that do not hold a primitive value. */
String strVal2; String strVal2;
/** Third part of the value of this item, for items that do not hold a primitive value. */ /** Third part of the value of this item, for items that do not hold a primitive value. */
String strVal3; String strVal3;
/** The hash code value of this constant pool item. */ /** The hash code value of this constant pool item. */
int hashCode; int hashCode;
/** Link to another constant pool item, used for collision lists in the constant pool's hash table. */ /** Link to another constant pool item, used for collision lists in the constant pool's hash table. */
Item next; Item next;
/** Constructs an uninitialized {@link Item}. */ /** Constructs an uninitialized {@link Item}. */
Item() {} Item() {}
/** /**
* Constructs an uninitialized {@link Item} for constant pool element at given position. * Constructs an uninitialized {@link Item} for constant pool element at given position.
* *
* @param index index of the item to be constructed. * @param index index of the item to be constructed.
*/ */
Item(final int index) { Item(final int index) {
this.index = index; this.index = index;
} }
/** /**
* Constructs a copy of the given item. * Constructs a copy of the given item.
* *
* @param index index of the item to be constructed. * @param index index of the item to be constructed.
* @param i the item that must be copied into the item to be constructed. * @param i the item that must be copied into the item to be constructed.
*/ */
Item(final int index, final Item i) { Item(final int index, final Item i) {
this.index = index; this.index = index;
type = i.type; type = i.type;
intVal = i.intVal; intVal = i.intVal;
longVal = i.longVal; longVal = i.longVal;
strVal1 = i.strVal1; strVal1 = i.strVal1;
strVal2 = i.strVal2; strVal2 = i.strVal2;
strVal3 = i.strVal3; strVal3 = i.strVal3;
hashCode = i.hashCode; hashCode = i.hashCode;
} }
/** /**
* Sets this item to an integer item. * Sets this item to an integer item.
* *
* @param intVal the value of this item. * @param intVal the value of this item.
*/ */
void set(final int intVal) { void set(final int intVal) {
this.type = ClassWriter.INT; this.type = ClassWriter.INT;
this.intVal = intVal; this.intVal = intVal;
this.hashCode = 0x7FFFFFFF & (type + intVal); this.hashCode = 0x7FFFFFFF & (type + intVal);
} }
/** /**
* Sets this item to a long item. * Sets this item to a long item.
* *
* @param longVal the value of this item. * @param longVal the value of this item.
*/ */
void set(final long longVal) { void set(final long longVal) {
this.type = ClassWriter.LONG; this.type = ClassWriter.LONG;
this.longVal = longVal; this.longVal = longVal;
this.hashCode = 0x7FFFFFFF & (type + (int) longVal); this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
} }
/** /**
* Sets this item to a float item. * Sets this item to a float item.
* *
* @param floatVal the value of this item. * @param floatVal the value of this item.
*/ */
void set(final float floatVal) { void set(final float floatVal) {
this.type = ClassWriter.FLOAT; this.type = ClassWriter.FLOAT;
this.intVal = Float.floatToRawIntBits(floatVal); this.intVal = Float.floatToRawIntBits(floatVal);
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
} }
/** /**
* Sets this item to a double item. * Sets this item to a double item.
* *
* @param doubleVal the value of this item. * @param doubleVal the value of this item.
*/ */
void set(final double doubleVal) { void set(final double doubleVal) {
this.type = ClassWriter.DOUBLE; this.type = ClassWriter.DOUBLE;
this.longVal = Double.doubleToRawLongBits(doubleVal); this.longVal = Double.doubleToRawLongBits(doubleVal);
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
} }
/** /**
* Sets this item to an item that do not hold a primitive value. * Sets this item to an item that do not hold a primitive value.
* *
* @param type the type of this item. * @param type the type of this item.
* @param strVal1 first part of the value of this item. * @param strVal1 first part of the value of this item.
* @param strVal2 second part of the value of this item. * @param strVal2 second part of the value of this item.
* @param strVal3 third part of the value of this item. * @param strVal3 third part of the value of this item.
*/ */
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
void set(final int type, final String strVal1, final String strVal2, final String strVal3) { void set(final int type, final String strVal1, final String strVal2, final String strVal3) {
this.type = type; this.type = type;
this.strVal1 = strVal1; this.strVal1 = strVal1;
this.strVal2 = strVal2; this.strVal2 = strVal2;
this.strVal3 = strVal3; this.strVal3 = strVal3;
switch (type) { switch (type) {
case ClassWriter.CLASS: case ClassWriter.CLASS:
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
case ClassWriter.UTF8: case ClassWriter.UTF8:
case ClassWriter.STR: case ClassWriter.STR:
case ClassWriter.MTYPE: case ClassWriter.MTYPE:
case ClassWriter.MODULE: case ClassWriter.MODULE:
case ClassWriter.PACKAGE: case ClassWriter.PACKAGE:
case ClassWriter.TYPE_NORMAL: case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return; return;
case ClassWriter.NAME_TYPE: { case ClassWriter.NAME_TYPE: {
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode()); hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode());
return; return;
} }
// ClassWriter.FIELD: // ClassWriter.FIELD:
// ClassWriter.METH: // ClassWriter.METH:
// ClassWriter.IMETH: // ClassWriter.IMETH:
// ClassWriter.HANDLE_BASE + 1..9 // ClassWriter.HANDLE_BASE + 1..9
default: default:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode()); hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode());
} }
} }
/** /**
* Sets the item to an InvokeDynamic item. * Sets the item to an InvokeDynamic item.
* *
* @param name invokedynamic's name. * @param name invokedynamic's name.
* @param desc invokedynamic's desc. * @param desc invokedynamic's desc.
* @param bsmIndex zero based index into the class attribute BootrapMethods. * @param bsmIndex zero based index into the class attribute BootrapMethods.
*/ */
void set(String name, String desc, int bsmIndex) { void set(String name, String desc, int bsmIndex) {
this.type = ClassWriter.INDY; this.type = ClassWriter.INDY;
this.longVal = bsmIndex; this.longVal = bsmIndex;
this.strVal1 = name; this.strVal1 = name;
this.strVal2 = desc; this.strVal2 = desc;
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex * strVal1.hashCode() * strVal2.hashCode()); this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex * strVal1.hashCode() * strVal2.hashCode());
} }
/** /**
* Sets the item to a BootstrapMethod item. * Sets the item to a BootstrapMethod item.
* *
* @param position position in byte in the class attribute BootrapMethods. * @param position position in byte in the class attribute BootrapMethods.
* @param hashCode hashcode of the item. This hashcode is processed from the hashcode of the bootstrap method and * @param hashCode hashcode of the item. This hashcode is processed from the hashcode of the bootstrap method and
* the hashcode of all bootstrap arguments. * the hashcode of all bootstrap arguments.
*/ */
void set(int position, int hashCode) { void set(int position, int hashCode) {
this.type = ClassWriter.BSM; this.type = ClassWriter.BSM;
this.intVal = position; this.intVal = position;
this.hashCode = hashCode; this.hashCode = hashCode;
} }
/** /**
* Indicates if the given item is equal to this one. <i>This method assumes that the two items have the same * Indicates if the given item is equal to this one. <i>This method assumes that the two items have the same
* {@link #type}</i>. * {@link #type}</i>.
* *
* @param i the item to be compared to this one. Both items must have the same {@link #type}. * @param i the item to be compared to this one. Both items must have the same {@link #type}.
* @return &#60;tt&#62;true&#60;/tt&#62; if the given item if equal to this one, &#60;tt&#62;false&#60;/tt&#62; * @return &#60;tt&#62;true&#60;/tt&#62; if the given item if equal to this one, &#60;tt&#62;false&#60;/tt&#62;
* otherwise. * otherwise.
*/ */
boolean isEqualTo(final Item i) { boolean isEqualTo(final Item i) {
switch (type) { switch (type) {
case ClassWriter.UTF8: case ClassWriter.UTF8:
case ClassWriter.STR: case ClassWriter.STR:
case ClassWriter.CLASS: case ClassWriter.CLASS:
case ClassWriter.MODULE: case ClassWriter.MODULE:
case ClassWriter.PACKAGE: case ClassWriter.PACKAGE:
case ClassWriter.MTYPE: case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL: case ClassWriter.TYPE_NORMAL:
return i.strVal1.equals(strVal1); return i.strVal1.equals(strVal1);
case ClassWriter.TYPE_MERGED: case ClassWriter.TYPE_MERGED:
case ClassWriter.LONG: case ClassWriter.LONG:
case ClassWriter.DOUBLE: case ClassWriter.DOUBLE:
return i.longVal == longVal; return i.longVal == longVal;
case ClassWriter.INT: case ClassWriter.INT:
case ClassWriter.FLOAT: case ClassWriter.FLOAT:
return i.intVal == intVal; return i.intVal == intVal;
case ClassWriter.TYPE_UNINIT: case ClassWriter.TYPE_UNINIT:
return i.intVal == intVal && i.strVal1.equals(strVal1); return i.intVal == intVal && i.strVal1.equals(strVal1);
case ClassWriter.NAME_TYPE: case ClassWriter.NAME_TYPE:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
case ClassWriter.INDY: { case ClassWriter.INDY: {
return i.longVal == longVal && i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); return i.longVal == longVal && i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
} }
// case ClassWriter.FIELD: // case ClassWriter.FIELD:
// case ClassWriter.METH: // case ClassWriter.METH:
// case ClassWriter.IMETH: // case ClassWriter.IMETH:
// case ClassWriter.HANDLE_BASE + 1..9 // case ClassWriter.HANDLE_BASE + 1..9
default: default:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3); return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3);
} }
} }
} }

View File

@@ -68,442 +68,442 @@ package org.redkale.asm;
*/ */
public class Label { public class Label {
/** /**
* Indicates if this label is only used for debug attributes. Such a label is not the start of a basic block, the * Indicates if this label is only used for debug attributes. Such a label is not the start of a basic block, the
* target of a jump instruction, or an exception handler. It can be safely ignored in control flow graph analysis * target of a jump instruction, or an exception handler. It can be safely ignored in control flow graph analysis
* algorithms (for optimization purposes). * algorithms (for optimization purposes).
*/ */
static final int DEBUG = 1; static final int DEBUG = 1;
/** Indicates if the position of this label is known. */ /** Indicates if the position of this label is known. */
static final int RESOLVED = 2; static final int RESOLVED = 2;
/** Indicates if this label has been updated, after instruction resizing. */ /** Indicates if this label has been updated, after instruction resizing. */
static final int RESIZED = 4; static final int RESIZED = 4;
/** /**
* Indicates if this basic block has been pushed in the basic block stack. See {@link MethodWriter#visitMaxs * Indicates if this basic block has been pushed in the basic block stack. See {@link MethodWriter#visitMaxs
* visitMaxs}. * visitMaxs}.
*/ */
static final int PUSHED = 8; static final int PUSHED = 8;
/** Indicates if this label is the target of a jump instruction, or the start of an exception handler. */ /** Indicates if this label is the target of a jump instruction, or the start of an exception handler. */
static final int TARGET = 16; static final int TARGET = 16;
/** Indicates if a stack map frame must be stored for this label. */ /** Indicates if a stack map frame must be stored for this label. */
static final int STORE = 32; static final int STORE = 32;
/** Indicates if this label corresponds to a reachable basic block. */ /** Indicates if this label corresponds to a reachable basic block. */
static final int REACHABLE = 64; static final int REACHABLE = 64;
/** Indicates if this basic block ends with a JSR instruction. */ /** Indicates if this basic block ends with a JSR instruction. */
static final int JSR = 128; static final int JSR = 128;
/** Indicates if this basic block ends with a RET instruction. */ /** Indicates if this basic block ends with a RET instruction. */
static final int RET = 256; static final int RET = 256;
/** Indicates if this basic block is the start of a subroutine. */ /** Indicates if this basic block is the start of a subroutine. */
static final int SUBROUTINE = 512; static final int SUBROUTINE = 512;
/** Indicates if this subroutine basic block has been visited by a visitSubroutine(null, ...) call. */ /** Indicates if this subroutine basic block has been visited by a visitSubroutine(null, ...) call. */
static final int VISITED = 1024; static final int VISITED = 1024;
/** Indicates if this subroutine basic block has been visited by a visitSubroutine(!null, ...) call. */ /** Indicates if this subroutine basic block has been visited by a visitSubroutine(!null, ...) call. */
static final int VISITED2 = 2048; static final int VISITED2 = 2048;
/** /**
* Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In * Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In
* order to use it with the ASM tree package you must override the * order to use it with the ASM tree package you must override the
*/ */
public Object info; public Object info;
/** /**
* Flags that indicate the status of this label. * Flags that indicate the status of this label.
* *
* @see #DEBUG * @see #DEBUG
* @see #RESOLVED * @see #RESOLVED
* @see #RESIZED * @see #RESIZED
* @see #PUSHED * @see #PUSHED
* @see #TARGET * @see #TARGET
* @see #STORE * @see #STORE
* @see #REACHABLE * @see #REACHABLE
* @see #JSR * @see #JSR
* @see #RET * @see #RET
*/ */
int status; int status;
/** /**
* The line number corresponding to this label, if known. If there are several lines, each line is stored in a * The line number corresponding to this label, if known. If there are several lines, each line is stored in a
* separate label, all linked via their next field (these links are created in ClassReader and removed just before * separate label, all linked via their next field (these links are created in ClassReader and removed just before
* visitLabel is called, so that this does not impact the rest of the code). * visitLabel is called, so that this does not impact the rest of the code).
*/ */
int line; int line;
/** The position of this label in the code, if known. */ /** The position of this label in the code, if known. */
int position; int position;
/** Number of forward references to this label, times two. */ /** Number of forward references to this label, times two. */
private int referenceCount; private int referenceCount;
/** /**
* Informations about forward references. Each forward reference is described by two consecutive integers in this * Informations about forward references. Each forward reference is described by two consecutive integers in this
* array: the first one is the position of the first byte of the bytecode instruction that contains the forward * array: the first one is the position of the first byte of the bytecode instruction that contains the forward
* reference, while the second is the position of the first byte of the forward reference itself. In fact the sign * reference, while the second is the position of the first byte of the forward reference itself. In fact the sign
* of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of * of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of
* the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block * the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block
* belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been * belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been
* resolved. Hence the same array can be used for both purposes without problems. * resolved. Hence the same array can be used for both purposes without problems.
*/ */
private int[] srcAndRefPositions; private int[] srcAndRefPositions;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/* /*
* Fields for the control flow and data flow graph analysis algorithms (used * Fields for the control flow and data flow graph analysis algorithms (used
* to compute the maximum stack size or the stack map frames). A control * to compute the maximum stack size or the stack map frames). A control
* flow graph contains one node per "basic block", and one edge per "jump" * flow graph contains one node per "basic block", and one edge per "jump"
* from one basic block to another. Each node (i.e., each basic block) is * from one basic block to another. Each node (i.e., each basic block) is
* represented by the Label object that corresponds to the first instruction * represented by the Label object that corresponds to the first instruction
* of this basic block. Each node also stores the list of its successors in * of this basic block. Each node also stores the list of its successors in
* the graph, as a linked list of Edge objects. * the graph, as a linked list of Edge objects.
* *
* The control flow analysis algorithms used to compute the maximum stack * The control flow analysis algorithms used to compute the maximum stack
* size or the stack map frames are similar and use two steps. The first * size or the stack map frames are similar and use two steps. The first
* step, during the visit of each instruction, builds information about the * step, during the visit of each instruction, builds information about the
* state of the local variables and the operand stack at the end of each * state of the local variables and the operand stack at the end of each
* basic block, called the "output frame", <i>relatively</i> to the frame * basic block, called the "output frame", <i>relatively</i> to the frame
* state at the beginning of the basic block, which is called the "input * state at the beginning of the basic block, which is called the "input
* frame", and which is <i>unknown</i> during this step. The second step, in * frame", and which is <i>unknown</i> during this step. The second step, in
* {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
* information about the input frame of each basic block, from the input * information about the input frame of each basic block, from the input
* state of the first basic block (known from the method signature), and by * state of the first basic block (known from the method signature), and by
* the using the previously computed relative output frames. * the using the previously computed relative output frames.
* *
* The algorithm used to compute the maximum stack size only computes the * The algorithm used to compute the maximum stack size only computes the
* relative output and absolute input stack heights, while the algorithm * relative output and absolute input stack heights, while the algorithm
* used to compute stack map frames computes relative output frames and * used to compute stack map frames computes relative output frames and
* absolute input frames. * absolute input frames.
*/ */
/** /**
* Start of the output stack relatively to the input stack. The exact semantics of this field depends on the * Start of the output stack relatively to the input stack. The exact semantics of this field depends on the
* algorithm that is used. * algorithm that is used.
* *
* <p>When only the maximum stack size is computed, this field is the number of elements in the input stack. * <p>When only the maximum stack size is computed, this field is the number of elements in the input stack.
* *
* <p>When the stack map frames are completely computed, this field is the offset of the first output stack element * <p>When the stack map frames are completely computed, this field is the offset of the first output stack element
* relatively to the top of the input stack. This offset is always negative or null. A null offset means that the * relatively to the top of the input stack. This offset is always negative or null. A null offset means that the
* output stack must be appended to the input stack. A -n offset means that the first n output stack elements must * output stack must be appended to the input stack. A -n offset means that the first n output stack elements must
* replace the top n input stack elements, and that the other elements must be appended to the input stack. * replace the top n input stack elements, and that the other elements must be appended to the input stack.
*/ */
int inputStackTop; int inputStackTop;
/** /**
* Maximum height reached by the output stack, relatively to the top of the input stack. This maximum is always * Maximum height reached by the output stack, relatively to the top of the input stack. This maximum is always
* positive or null. * positive or null.
*/ */
int outputStackMax; int outputStackMax;
/** /**
* Information about the input and output stack map frames of this basic block. This field is only used when * Information about the input and output stack map frames of this basic block. This field is only used when
* {@link ClassWriter#COMPUTE_FRAMES} option is used. * {@link ClassWriter#COMPUTE_FRAMES} option is used.
*/ */
Frame frame; Frame frame;
/** /**
* The successor of this label, in the order they are visited. This linked list does not include labels used for * The successor of this label, in the order they are visited. This linked list does not include labels used for
* debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain * debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain
* successive labels that denote the same bytecode position (in this case only the first label appears in this * successive labels that denote the same bytecode position (in this case only the first label appears in this
* list). * list).
*/ */
Label successor; Label successor;
/** /**
* The successors of this node in the control flow graph. These successors are stored in a linked list of * The successors of this node in the control flow graph. These successors are stored in a linked list of
* {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field. * {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field.
*/ */
Edge successors; Edge successors;
/** /**
* The next basic block in the basic block stack. This stack is used in the main loop of the fix point algorithm * The next basic block in the basic block stack. This stack is used in the main loop of the fix point algorithm
* used in the second step of the control flow analysis algorithms. It is also used in {@link #visitSubroutine} to * used in the second step of the control flow analysis algorithms. It is also used in {@link #visitSubroutine} to
* avoid using a recursive method, and in ClassReader to temporarily store multiple source lines for a label. * avoid using a recursive method, and in ClassReader to temporarily store multiple source lines for a label.
* *
* @see MethodWriter#visitMaxs * @see MethodWriter#visitMaxs
*/ */
Label next; Label next;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Constructor // Constructor
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Constructs a new label. */ /** Constructs a new label. */
public Label() { public Label() {
// do nothing // do nothing
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Methods to compute offsets and to manage forward references // Methods to compute offsets and to manage forward references
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Returns the offset corresponding to this label. This offset is computed from the start of the method's bytecode. * Returns the offset corresponding to this label. This offset is computed from the start of the method's bytecode.
* <i>This method is intended for {@link Attribute} sub classes, and is normally not needed by class generators or * <i>This method is intended for {@link Attribute} sub classes, and is normally not needed by class generators or
* adapters.</i> * adapters.</i>
* *
* @return the offset corresponding to this label. * @return the offset corresponding to this label.
* @throws IllegalStateException if this label is not resolved yet. * @throws IllegalStateException if this label is not resolved yet.
*/ */
public int getOffset() { public int getOffset() {
if ((status & RESOLVED) == 0) { if ((status & RESOLVED) == 0) {
throw new IllegalStateException("Label offset position has not been resolved yet"); throw new IllegalStateException("Label offset position has not been resolved yet");
} }
return position; return position;
} }
/** /**
* Puts a reference to this label in the bytecode of a method. If the position of the label is known, the offset is * Puts a reference to this label in the bytecode of a method. If the position of the label is known, the offset is
* computed and written directly. Otherwise, a null offset is written and a new forward reference is declared for * computed and written directly. Otherwise, a null offset is written and a new forward reference is declared for
* this label. * this label.
* *
* @param owner the code writer that calls this method. * @param owner the code writer that calls this method.
* @param out the bytecode of the method. * @param out the bytecode of the method.
* @param source the position of first byte of the bytecode instruction that contains this label. * @param source the position of first byte of the bytecode instruction that contains this label.
* @param wideOffset &#60;tt&#62;true&#60;/tt&#62; if the reference must be stored in 4 bytes, or * @param wideOffset &#60;tt&#62;true&#60;/tt&#62; if the reference must be stored in 4 bytes, or
* &#60;tt&#62;false&#60;/tt&#62; if it must be stored with 2 bytes. * &#60;tt&#62;false&#60;/tt&#62; if it must be stored with 2 bytes.
* @throws IllegalArgumentException if this label has not been created by the given code writer. * @throws IllegalArgumentException if this label has not been created by the given code writer.
*/ */
void put(final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) { void put(final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) {
if ((status & RESOLVED) == 0) { if ((status & RESOLVED) == 0) {
if (wideOffset) { if (wideOffset) {
addReference(-1 - source, out.length); addReference(-1 - source, out.length);
out.putInt(-1); out.putInt(-1);
} else { } else {
addReference(source, out.length); addReference(source, out.length);
out.putShort(-1); out.putShort(-1);
} }
} else { } else {
if (wideOffset) { if (wideOffset) {
out.putInt(position - source); out.putInt(position - source);
} else { } else {
out.putShort(position - source); out.putShort(position - source);
} }
} }
} }
/** /**
* Adds a forward reference to this label. This method must be called only for a true forward reference, i.e. only * Adds a forward reference to this label. This method must be called only for a true forward reference, i.e. only
* if this label is not resolved yet. For backward references, the offset of the reference can be, and must be, * if this label is not resolved yet. For backward references, the offset of the reference can be, and must be,
* computed and stored directly. * computed and stored directly.
* *
* @param sourcePosition the position of the referencing instruction. This position will be used to compute the * @param sourcePosition the position of the referencing instruction. This position will be used to compute the
* offset of this forward reference. * offset of this forward reference.
* @param referencePosition the position where the offset for this forward reference must be stored. * @param referencePosition the position where the offset for this forward reference must be stored.
*/ */
private void addReference(final int sourcePosition, final int referencePosition) { private void addReference(final int sourcePosition, final int referencePosition) {
if (srcAndRefPositions == null) { if (srcAndRefPositions == null) {
srcAndRefPositions = new int[6]; srcAndRefPositions = new int[6];
} }
if (referenceCount >= srcAndRefPositions.length) { if (referenceCount >= srcAndRefPositions.length) {
int[] a = new int[srcAndRefPositions.length + 6]; int[] a = new int[srcAndRefPositions.length + 6];
System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length); System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
srcAndRefPositions = a; srcAndRefPositions = a;
} }
srcAndRefPositions[referenceCount++] = sourcePosition; srcAndRefPositions[referenceCount++] = sourcePosition;
srcAndRefPositions[referenceCount++] = referencePosition; srcAndRefPositions[referenceCount++] = referencePosition;
} }
/** /**
* Resolves all forward references to this label. This method must be called when this label is added to the * Resolves all forward references to this label. This method must be called when this label is added to the
* bytecode of the method, i.e. when its position becomes known. This method fills in the blanks that where left in * bytecode of the method, i.e. when its position becomes known. This method fills in the blanks that where left in
* the bytecode by each forward reference previously added to this label. * the bytecode by each forward reference previously added to this label.
* *
* @param owner the code writer that calls this method. * @param owner the code writer that calls this method.
* @param position the position of this label in the bytecode. * @param position the position of this label in the bytecode.
* @param data the bytecode of the method. * @param data the bytecode of the method.
* @return &#60;tt&#62;true&#60;/tt&#62; if a blank that was left for this label was too small to store the offset. * @return &#60;tt&#62;true&#60;/tt&#62; if a blank that was left for this label was too small to store the offset.
* In such a case the corresponding jump instruction is replaced with a pseudo instruction (using unused * In such a case the corresponding jump instruction is replaced with a pseudo instruction (using unused
* opcodes) using an unsigned two bytes offset. These pseudo instructions will be replaced with standard * opcodes) using an unsigned two bytes offset. These pseudo instructions will be replaced with standard
* bytecode instructions with wider offsets (4 bytes instead of 2), in ClassReader. * bytecode instructions with wider offsets (4 bytes instead of 2), in ClassReader.
* @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the * @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the
* given code writer. * given code writer.
*/ */
boolean resolve(final MethodWriter owner, final int position, final byte[] data) { boolean resolve(final MethodWriter owner, final int position, final byte[] data) {
boolean needUpdate = false; boolean needUpdate = false;
this.status |= RESOLVED; this.status |= RESOLVED;
this.position = position; this.position = position;
int i = 0; int i = 0;
while (i < referenceCount) { while (i < referenceCount) {
int source = srcAndRefPositions[i++]; int source = srcAndRefPositions[i++];
int reference = srcAndRefPositions[i++]; int reference = srcAndRefPositions[i++];
int offset; int offset;
if (source >= 0) { if (source >= 0) {
offset = position - source; offset = position - source;
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
/* /*
* changes the opcode of the jump instruction, in order to * changes the opcode of the jump instruction, in order to
* be able to find it later (see resizeInstructions in * be able to find it later (see resizeInstructions in
* MethodWriter). These temporary opcodes are similar to * MethodWriter). These temporary opcodes are similar to
* jump instruction opcodes, except that the 2 bytes offset * jump instruction opcodes, except that the 2 bytes offset
* is unsigned (and can therefore represent values from 0 to * is unsigned (and can therefore represent values from 0 to
* 65535, which is sufficient since the size of a method is * 65535, which is sufficient since the size of a method is
* limited to 65535 bytes). * limited to 65535 bytes).
*/ */
int opcode = data[reference - 1] & 0xFF; int opcode = data[reference - 1] & 0xFF;
if (opcode <= Opcodes.JSR) { if (opcode <= Opcodes.JSR) {
// changes IFEQ ... JSR to opcodes 202 to 217 // changes IFEQ ... JSR to opcodes 202 to 217
data[reference - 1] = (byte) (opcode + 49); data[reference - 1] = (byte) (opcode + 49);
} else { } else {
// changes IFNULL and IFNONNULL to opcodes 218 and 219 // changes IFNULL and IFNONNULL to opcodes 218 and 219
data[reference - 1] = (byte) (opcode + 20); data[reference - 1] = (byte) (opcode + 20);
} }
needUpdate = true; needUpdate = true;
} }
data[reference++] = (byte) (offset >>> 8); data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset; data[reference] = (byte) offset;
} else { } else {
offset = position + source + 1; offset = position + source + 1;
data[reference++] = (byte) (offset >>> 24); data[reference++] = (byte) (offset >>> 24);
data[reference++] = (byte) (offset >>> 16); data[reference++] = (byte) (offset >>> 16);
data[reference++] = (byte) (offset >>> 8); data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset; data[reference] = (byte) offset;
} }
} }
return needUpdate; return needUpdate;
} }
/** /**
* Returns the first label of the series to which this label belongs. For an isolated label or for the first label * Returns the first label of the series to which this label belongs. For an isolated label or for the first label
* in a series of successive labels, this method returns the label itself. For other labels it returns the first * in a series of successive labels, this method returns the label itself. For other labels it returns the first
* label of the series. * label of the series.
* *
* @return the first label of the series to which this label belongs. * @return the first label of the series to which this label belongs.
*/ */
Label getFirst() { Label getFirst() {
return frame == null ? this : frame.owner; return frame == null ? this : frame.owner;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Methods related to subroutines // Methods related to subroutines
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Returns true is this basic block belongs to the given subroutine. * Returns true is this basic block belongs to the given subroutine.
* *
* @param id a subroutine id. * @param id a subroutine id.
* @return true is this basic block belongs to the given subroutine. * @return true is this basic block belongs to the given subroutine.
*/ */
boolean inSubroutine(final long id) { boolean inSubroutine(final long id) {
if ((status & Label.VISITED) != 0) { if ((status & Label.VISITED) != 0) {
return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0; return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
} }
return false; return false;
} }
/** /**
* Returns true if this basic block and the given one belong to a common subroutine. * Returns true if this basic block and the given one belong to a common subroutine.
* *
* @param block another basic block. * @param block another basic block.
* @return true if this basic block and the given one belong to a common subroutine. * @return true if this basic block and the given one belong to a common subroutine.
*/ */
boolean inSameSubroutine(final Label block) { boolean inSameSubroutine(final Label block) {
if ((status & VISITED) == 0 || (block.status & VISITED) == 0) { if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
return false; return false;
} }
for (int i = 0; i < srcAndRefPositions.length; ++i) { for (int i = 0; i < srcAndRefPositions.length; ++i) {
if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) { if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
return true; return true;
} }
} }
return false; return false;
} }
/** /**
* Marks this basic block as belonging to the given subroutine. * Marks this basic block as belonging to the given subroutine.
* *
* @param id a subroutine id. * @param id a subroutine id.
* @param nbSubroutines the total number of subroutines in the method. * @param nbSubroutines the total number of subroutines in the method.
*/ */
void addToSubroutine(final long id, final int nbSubroutines) { void addToSubroutine(final long id, final int nbSubroutines) {
if ((status & VISITED) == 0) { if ((status & VISITED) == 0) {
status |= VISITED; status |= VISITED;
srcAndRefPositions = new int[nbSubroutines / 32 + 1]; srcAndRefPositions = new int[nbSubroutines / 32 + 1];
} }
srcAndRefPositions[(int) (id >>> 32)] |= (int) id; srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
} }
/** /**
* Finds the basic blocks that belong to a given subroutine, and marks these blocks as belonging to this subroutine. * Finds the basic blocks that belong to a given subroutine, and marks these blocks as belonging to this subroutine.
* This method follows the control flow graph to find all the blocks that are reachable from the current block * This method follows the control flow graph to find all the blocks that are reachable from the current block
* WITHOUT following any JSR target. * WITHOUT following any JSR target.
* *
* @param JSR a JSR block that jumps to this subroutine. If this JSR is not null it is added to the successor of the * @param JSR a JSR block that jumps to this subroutine. If this JSR is not null it is added to the successor of the
* RET blocks found in the subroutine. * RET blocks found in the subroutine.
* @param id the id of this subroutine. * @param id the id of this subroutine.
* @param nbSubroutines the total number of subroutines in the method. * @param nbSubroutines the total number of subroutines in the method.
*/ */
void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) { void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
// user managed stack of labels, to avoid using a recursive method // user managed stack of labels, to avoid using a recursive method
// (recursivity can lead to stack overflow with very large methods) // (recursivity can lead to stack overflow with very large methods)
Label stack = this; Label stack = this;
while (stack != null) { while (stack != null) {
// removes a label l from the stack // removes a label l from the stack
Label l = stack; Label l = stack;
stack = l.next; stack = l.next;
l.next = null; l.next = null;
if (JSR != null) { if (JSR != null) {
if ((l.status & VISITED2) != 0) { if ((l.status & VISITED2) != 0) {
continue; continue;
} }
l.status |= VISITED2; l.status |= VISITED2;
// adds JSR to the successors of l, if it is a RET block // adds JSR to the successors of l, if it is a RET block
if ((l.status & RET) != 0) { if ((l.status & RET) != 0) {
if (!l.inSameSubroutine(JSR)) { if (!l.inSameSubroutine(JSR)) {
Edge e = new Edge(); Edge e = new Edge();
e.info = l.inputStackTop; e.info = l.inputStackTop;
e.successor = JSR.successors.successor; e.successor = JSR.successors.successor;
e.next = l.successors; e.next = l.successors;
l.successors = e; l.successors = e;
} }
} }
} else { } else {
// if the l block already belongs to subroutine 'id', continue // if the l block already belongs to subroutine 'id', continue
if (l.inSubroutine(id)) { if (l.inSubroutine(id)) {
continue; continue;
} }
// marks the l block as belonging to subroutine 'id' // marks the l block as belonging to subroutine 'id'
l.addToSubroutine(id, nbSubroutines); l.addToSubroutine(id, nbSubroutines);
} }
// pushes each successor of l on the stack, except JSR targets // pushes each successor of l on the stack, except JSR targets
Edge e = l.successors; Edge e = l.successors;
while (e != null) { while (e != null) {
// if the l block is a JSR block, then 'l.successors.next' leads // if the l block is a JSR block, then 'l.successors.next' leads
// to the JSR target (see {@link #visitJumpInsn}) and must // to the JSR target (see {@link #visitJumpInsn}) and must
// therefore not be followed // therefore not be followed
if ((l.status & Label.JSR) == 0 || e != l.successors.next) { if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
// pushes e.successor on the stack if it not already added // pushes e.successor on the stack if it not already added
if (e.successor.next == null) { if (e.successor.next == null) {
e.successor.next = stack; e.successor.next = stack;
stack = e.successor; stack = e.successor;
} }
} }
e = e.next; e = e.next;
} }
} }
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Overriden Object methods // Overriden Object methods
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** /**
* Returns a string representation of this label. * Returns a string representation of this label.
* *
* @return a string representation of this label. * @return a string representation of this label.
*/ */
@Override @Override
public String toString() { public String toString() {
return "L" + System.identityHashCode(this); return "L" + System.identityHashCode(this);
} }
} }

View File

@@ -16,248 +16,248 @@ import java.util.*;
*/ */
public class MethodDebugVisitor extends MethodVisitor { public class MethodDebugVisitor extends MethodVisitor {
private final MethodVisitor visitor; private final MethodVisitor visitor;
private boolean debug = false; private boolean debug = false;
public MethodDebugVisitor setDebug(boolean d) { public MethodDebugVisitor setDebug(boolean d) {
debug = d; debug = d;
return this; return this;
} }
public void debugLine() { public void debugLine() {
if (!debug) { if (!debug) {
return; return;
} }
System.out.println(); System.out.println();
System.out.println(); System.out.println();
System.out.println(); System.out.println();
} }
private final Map<Label, Integer> labels = new LinkedHashMap<>(); private final Map<Label, Integer> labels = new LinkedHashMap<>();
private static final String[] opcodes = new String[200]; // 0 -18 private static final String[] opcodes = new String[200]; // 0 -18
static { static {
try { try {
for (java.lang.reflect.Field field : Opcodes.class.getFields()) { for (java.lang.reflect.Field field : Opcodes.class.getFields()) {
String name = field.getName(); String name = field.getName();
if (name.startsWith("ASM")) { if (name.startsWith("ASM")) {
continue; continue;
} }
if (name.startsWith("V1_")) { if (name.startsWith("V1_")) {
continue; continue;
} }
if (name.startsWith("ACC_")) { if (name.startsWith("ACC_")) {
continue; continue;
} }
if (name.startsWith("T_")) { if (name.startsWith("T_")) {
continue; continue;
} }
if (name.startsWith("H_")) { if (name.startsWith("H_")) {
continue; continue;
} }
if (name.startsWith("F_")) { if (name.startsWith("F_")) {
continue; continue;
} }
if (field.getType() != int.class) { if (field.getType() != int.class) {
continue; continue;
} }
opcodes[(int) (Integer) field.get(null)] = name; opcodes[(int) (Integer) field.get(null)] = name;
} }
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException(ex); // 不可能会发生 throw new RuntimeException(ex); // 不可能会发生
} }
} }
/** @param visitor MethodVisitor */ /** @param visitor MethodVisitor */
public MethodDebugVisitor(MethodVisitor visitor) { public MethodDebugVisitor(MethodVisitor visitor) {
super(Opcodes.ASM6, visitor); super(Opcodes.ASM6, visitor);
this.visitor = visitor; this.visitor = visitor;
} }
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
visitor.visitTryCatchBlock(start, end, handler, type); visitor.visitTryCatchBlock(start, end, handler, type);
if (debug) { if (debug) {
System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");"); System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");");
} }
} }
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) { public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln); AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln);
if (debug) { if (debug) {
System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");"); System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");");
} }
return av; return av;
} }
public AnnotationVisitor visitAnnotation(String desc, boolean flag) { public AnnotationVisitor visitAnnotation(String desc, boolean flag) {
AnnotationVisitor av = visitor.visitAnnotation(desc, flag); AnnotationVisitor av = visitor.visitAnnotation(desc, flag);
if (debug) { if (debug) {
System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");"); System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");");
} }
return av; return av;
} }
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible); AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible);
if (debug) { if (debug) {
System.out.println( System.out.println(
"mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");"); "mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");");
} }
return av; return av;
} }
public void visitParameter(String name, int access) { public void visitParameter(String name, int access) {
visitor.visitParameter(name, access); visitor.visitParameter(name, access);
if (debug) { if (debug) {
System.out.println("mv.visitParameter(" + name + ", " + access + ");"); System.out.println("mv.visitParameter(" + name + ", " + access + ");");
} }
} }
public void visitVarInsn(int opcode, int var) { public void visitVarInsn(int opcode, int var) {
visitor.visitVarInsn(opcode, var); visitor.visitVarInsn(opcode, var);
if (debug) { if (debug) {
System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");"); System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");");
} }
} }
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
visitor.visitFrame(type, nLocal, local, nStack, stack); visitor.visitFrame(type, nLocal, local, nStack, stack);
if (debug) { if (debug) {
String typestr = "" + type; String typestr = "" + type;
if (type == -1) { if (type == -1) {
typestr = "Opcodes.F_NEW"; typestr = "Opcodes.F_NEW";
} else if (type == 1) { } else if (type == 1) {
typestr = "Opcodes.F_APPEND"; typestr = "Opcodes.F_APPEND";
} else if (type == 2) { } else if (type == 2) {
typestr = "Opcodes.F_CHOP"; typestr = "Opcodes.F_CHOP";
} else if (type == 3) { } else if (type == 3) {
typestr = "Opcodes.F_SAME"; typestr = "Opcodes.F_SAME";
} else if (type == 4) { } else if (type == 4) {
typestr = "Opcodes.F_SAME1"; typestr = "Opcodes.F_SAME1";
} }
System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", " System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", "
+ nStack + ", " + Arrays.toString(stack) + ");"); + nStack + ", " + Arrays.toString(stack) + ");");
} }
} }
public void visitJumpInsn(int opcode, Label var) { // 调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建 public void visitJumpInsn(int opcode, Label var) { // 调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建
visitor.visitJumpInsn(opcode, var); visitor.visitJumpInsn(opcode, var);
if (debug) { if (debug) {
Integer index = labels.get(var); Integer index = labels.get(var);
if (index == null) { if (index == null) {
index = labels.size(); index = labels.size();
labels.put(var, index); labels.put(var, index);
System.out.println("Label l" + index + " = new Label();"); System.out.println("Label l" + index + " = new Label();");
} }
System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");"); System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");");
} }
} }
public void visitCode() { public void visitCode() {
visitor.visitCode(); visitor.visitCode();
if (debug) { if (debug) {
System.out.println("mv.visitCode();"); System.out.println("mv.visitCode();");
} }
} }
public void visitLabel(Label var) { public void visitLabel(Label var) {
visitor.visitLabel(var); visitor.visitLabel(var);
if (debug) { if (debug) {
Integer index = labels.get(var); Integer index = labels.get(var);
if (index == null) { if (index == null) {
index = labels.size(); index = labels.size();
labels.put(var, index); labels.put(var, index);
System.out.println("Label l" + index + " = new Label();"); System.out.println("Label l" + index + " = new Label();");
} }
System.out.println("mv.visitLabel(l" + index + ");"); System.out.println("mv.visitLabel(l" + index + ");");
} }
} }
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
visitor.visitMethodInsn(opcode, owner, name, desc, itf); visitor.visitMethodInsn(opcode, owner, name, desc, itf);
if (debug) { if (debug) {
System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \""
+ desc + "\", " + itf + ");"); + desc + "\", " + itf + ");");
} }
} }
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
visitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); visitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
if (debug) { if (debug) {
System.out.println("mv.visitInvokeDynamicInsn(\"" + name + "\", \"" + desc + "\", null, null);"); System.out.println("mv.visitInvokeDynamicInsn(\"" + name + "\", \"" + desc + "\", null, null);");
} }
} }
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
visitor.visitLocalVariable(name, desc, signature, start, end, index); visitor.visitLocalVariable(name, desc, signature, start, end, index);
if (debug) { if (debug) {
System.out.println("mv.visitLocalVariable(\"" + name + "\", \"" + desc + "\", \"" + signature System.out.println("mv.visitLocalVariable(\"" + name + "\", \"" + desc + "\", \"" + signature
+ "\", null, null, " + index + ");"); + "\", null, null, " + index + ");");
} }
} }
public void visitFieldInsn(int opcode, String owner, String name, String desc) { public void visitFieldInsn(int opcode, String owner, String name, String desc) {
visitor.visitFieldInsn(opcode, owner, name, desc); visitor.visitFieldInsn(opcode, owner, name, desc);
if (debug) { if (debug) {
System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \""
+ desc + "\");"); + desc + "\");");
} }
} }
public void visitTypeInsn(int opcode, String type) { public void visitTypeInsn(int opcode, String type) {
visitor.visitTypeInsn(opcode, type); visitor.visitTypeInsn(opcode, type);
if (debug) { if (debug) {
System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");"); System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");");
} }
} }
public void visitInsn(int opcode) { public void visitInsn(int opcode) {
visitor.visitInsn(opcode); visitor.visitInsn(opcode);
if (debug) { if (debug) {
System.out.println("mv.visitInsn(" + opcodes[opcode] + ");"); System.out.println("mv.visitInsn(" + opcodes[opcode] + ");");
} }
} }
public void visitIntInsn(int opcode, int value) { public void visitIntInsn(int opcode, int value) {
visitor.visitIntInsn(opcode, value); visitor.visitIntInsn(opcode, value);
if (debug) { if (debug) {
System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");"); System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");");
} }
} }
public void visitIincInsn(int opcode, int value) { public void visitIincInsn(int opcode, int value) {
visitor.visitIincInsn(opcode, value); visitor.visitIincInsn(opcode, value);
if (debug) { if (debug) {
System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");"); System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");");
} }
} }
public void visitLdcInsn(Object o) { public void visitLdcInsn(Object o) {
visitor.visitLdcInsn(o); visitor.visitLdcInsn(o);
if (debug) { if (debug) {
if (o instanceof CharSequence) { if (o instanceof CharSequence) {
System.out.println("mv.visitLdcInsn(\"" + o + "\");"); System.out.println("mv.visitLdcInsn(\"" + o + "\");");
} else if (o instanceof org.redkale.asm.Type) { } else if (o instanceof org.redkale.asm.Type) {
System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));"); System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
} else { } else {
System.out.println("mv.visitLdcInsn(" + o + ");"); System.out.println("mv.visitLdcInsn(" + o + ");");
} }
} }
} }
public void visitMaxs(int maxStack, int maxLocals) { public void visitMaxs(int maxStack, int maxLocals) {
visitor.visitMaxs(maxStack, maxLocals); visitor.visitMaxs(maxStack, maxLocals);
if (debug) { if (debug) {
System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");"); System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");");
} }
} }
public void visitEnd() { public void visitEnd() {
visitor.visitEnd(); visitor.visitEnd();
if (debug) { if (debug) {
System.out.println("mv.visitEnd();\r\n\r\n\r\n"); System.out.println("mv.visitEnd();\r\n\r\n\r\n");
} }
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -72,131 +72,131 @@ package org.redkale.asm;
* @author Remi Forax * @author Remi Forax
*/ */
public abstract class ModuleVisitor { public abstract class ModuleVisitor {
/** The ASM API version implemented by this visitor. The value of this field must be {@link Opcodes#ASM6}. */ /** The ASM API version implemented by this visitor. The value of this field must be {@link Opcodes#ASM6}. */
protected final int api; protected final int api;
/** The module visitor to which this visitor must delegate method calls. May be null. */ /** The module visitor to which this visitor must delegate method calls. May be null. */
protected ModuleVisitor mv; protected ModuleVisitor mv;
/** /**
* Constructs a new {@link ModuleVisitor}. * Constructs a new {@link ModuleVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
*/ */
public ModuleVisitor(final int api) { public ModuleVisitor(final int api) {
this(api, null); this(api, null);
} }
/** /**
* Constructs a new {@link ModuleVisitor}. * Constructs a new {@link ModuleVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
* @param mv the module visitor to which this visitor must delegate method calls. May be null. * @param mv the module visitor to which this visitor must delegate method calls. May be null.
*/ */
public ModuleVisitor(final int api, final ModuleVisitor mv) { public ModuleVisitor(final int api, final ModuleVisitor mv) {
if (api != Opcodes.ASM6) { if (api != Opcodes.ASM6) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
this.api = api; this.api = api;
this.mv = mv; this.mv = mv;
} }
/** /**
* Visit the main class of the current module. * Visit the main class of the current module.
* *
* @param mainClass the internal name of the main class of the current module. * @param mainClass the internal name of the main class of the current module.
*/ */
public void visitMainClass(String mainClass) { public void visitMainClass(String mainClass) {
if (mv != null) { if (mv != null) {
mv.visitMainClass(mainClass); mv.visitMainClass(mainClass);
} }
} }
/** /**
* Visit a package of the current module. * Visit a package of the current module.
* *
* @param packaze the qualified name of a package. * @param packaze the qualified name of a package.
*/ */
public void visitPackage(String packaze) { public void visitPackage(String packaze) {
if (mv != null) { if (mv != null) {
mv.visitPackage(packaze); mv.visitPackage(packaze);
} }
} }
/** /**
* Visits a dependence of the current module. * Visits a dependence of the current module.
* *
* @param module the qualified name of the dependence. * @param module the qualified name of the dependence.
* @param access the access flag of the dependence among ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC and * @param access the access flag of the dependence among ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC and
* ACC_MANDATED. * ACC_MANDATED.
* @param version the module version at compile time or null. * @param version the module version at compile time or null.
*/ */
public void visitRequire(String module, int access, String version) { public void visitRequire(String module, int access, String version) {
if (mv != null) { if (mv != null) {
mv.visitRequire(module, access, version); mv.visitRequire(module, access, version);
} }
} }
/** /**
* Visit an exported package of the current module. * Visit an exported package of the current module.
* *
* @param packaze the qualified name of the exported package. * @param packaze the qualified name of the exported package.
* @param access the access flag of the exported package, valid values are among {@code ACC_SYNTHETIC} and * @param access the access flag of the exported package, valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}. * {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can access to the public classes of the exported package * @param modules the qualified names of the modules that can access to the public classes of the exported package
* or &#60;tt&#62;null&#60;/tt&#62;. * or &#60;tt&#62;null&#60;/tt&#62;.
*/ */
public void visitExport(String packaze, int access, String... modules) { public void visitExport(String packaze, int access, String... modules) {
if (mv != null) { if (mv != null) {
mv.visitExport(packaze, access, modules); mv.visitExport(packaze, access, modules);
} }
} }
/** /**
* Visit an open package of the current module. * Visit an open package of the current module.
* *
* @param packaze the qualified name of the opened package. * @param packaze the qualified name of the opened package.
* @param access the access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and * @param access the access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}. * {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can use deep reflection to the classes of the open package * @param modules the qualified names of the modules that can use deep reflection to the classes of the open package
* or &#60;tt&#62;null&#60;/tt&#62;. * or &#60;tt&#62;null&#60;/tt&#62;.
*/ */
public void visitOpen(String packaze, int access, String... modules) { public void visitOpen(String packaze, int access, String... modules) {
if (mv != null) { if (mv != null) {
mv.visitOpen(packaze, access, modules); mv.visitOpen(packaze, access, modules);
} }
} }
/** /**
* Visit a service used by the current module. The name must be the internal name of an interface or a class. * Visit a service used by the current module. The name must be the internal name of an interface or a class.
* *
* @param service the internal name of the service. * @param service the internal name of the service.
*/ */
public void visitUse(String service) { public void visitUse(String service) {
if (mv != null) { if (mv != null) {
mv.visitUse(service); mv.visitUse(service);
} }
} }
/** /**
* Visit an implementation of a service. * Visit an implementation of a service.
* *
* @param service the internal name of the service * @param service the internal name of the service
* @param providers the internal names of the implementations of the service (there is at least one provider). * @param providers the internal names of the implementations of the service (there is at least one provider).
*/ */
public void visitProvide(String service, String... providers) { public void visitProvide(String service, String... providers) {
if (mv != null) { if (mv != null) {
mv.visitProvide(service, providers); mv.visitProvide(service, providers);
} }
} }
/** /**
* Visits the end of the module. This method, which is the last one to be called, is used to inform the visitor that * Visits the end of the module. This method, which is the last one to be called, is used to inform the visitor that
* everything have been visited. * everything have been visited.
*/ */
public void visitEnd() { public void visitEnd() {
if (mv != null) { if (mv != null) {
mv.visitEnd(); mv.visitEnd();
} }
} }
} }

View File

@@ -61,228 +61,228 @@ package org.redkale.asm;
/** @author Remi Forax */ /** @author Remi Forax */
final class ModuleWriter extends ModuleVisitor { final class ModuleWriter extends ModuleVisitor {
/** The class writer to which this Module attribute must be added. */ /** The class writer to which this Module attribute must be added. */
private final ClassWriter cw; private final ClassWriter cw;
/** size in byte of the Module attribute. */ /** size in byte of the Module attribute. */
int size; int size;
/** Number of attributes associated with the current module (Version, ConcealPackages, etc) */ /** Number of attributes associated with the current module (Version, ConcealPackages, etc) */
int attributeCount; int attributeCount;
/** Size in bytes of the attributes associated with the current module */ /** Size in bytes of the attributes associated with the current module */
int attributesSize; int attributesSize;
/** module name index in the constant pool */ /** module name index in the constant pool */
private final int name; private final int name;
/** module access flags */ /** module access flags */
private final int access; private final int access;
/** module version index in the constant pool or 0 */ /** module version index in the constant pool or 0 */
private final int version; private final int version;
/** module main class index in the constant pool or 0 */ /** module main class index in the constant pool or 0 */
private int mainClass; private int mainClass;
/** number of packages */ /** number of packages */
private int packageCount; private int packageCount;
/** /**
* The packages in bytecode form. This byte vector only contains the items themselves, the number of items is store * The packages in bytecode form. This byte vector only contains the items themselves, the number of items is store
* in packageCount * in packageCount
*/ */
private ByteVector packages; private ByteVector packages;
/** number of requires items */ /** number of requires items */
private int requireCount; private int requireCount;
/** /**
* The requires items in bytecode form. This byte vector only contains the items themselves, the number of items is * The requires items in bytecode form. This byte vector only contains the items themselves, the number of items is
* store in requireCount * store in requireCount
*/ */
private ByteVector requires; private ByteVector requires;
/** number of exports items */ /** number of exports items */
private int exportCount; private int exportCount;
/** /**
* The exports items in bytecode form. This byte vector only contains the items themselves, the number of items is * The exports items in bytecode form. This byte vector only contains the items themselves, the number of items is
* store in exportCount * store in exportCount
*/ */
private ByteVector exports; private ByteVector exports;
/** number of opens items */ /** number of opens items */
private int openCount; private int openCount;
/** /**
* The opens items in bytecode form. This byte vector only contains the items themselves, the number of items is * The opens items in bytecode form. This byte vector only contains the items themselves, the number of items is
* store in openCount * store in openCount
*/ */
private ByteVector opens; private ByteVector opens;
/** number of uses items */ /** number of uses items */
private int useCount; private int useCount;
/** /**
* The uses items in bytecode form. This byte vector only contains the items themselves, the number of items is * The uses items in bytecode form. This byte vector only contains the items themselves, the number of items is
* store in useCount * store in useCount
*/ */
private ByteVector uses; private ByteVector uses;
/** number of provides items */ /** number of provides items */
private int provideCount; private int provideCount;
/** /**
* The uses provides in bytecode form. This byte vector only contains the items themselves, the number of items is * The uses provides in bytecode form. This byte vector only contains the items themselves, the number of items is
* store in provideCount * store in provideCount
*/ */
private ByteVector provides; private ByteVector provides;
ModuleWriter(final ClassWriter cw, final int name, final int access, final int version) { ModuleWriter(final ClassWriter cw, final int name, final int access, final int version) {
super(Opcodes.ASM6); super(Opcodes.ASM6);
this.cw = cw; this.cw = cw;
this.size = 16; // name + access + version + 5 counts this.size = 16; // name + access + version + 5 counts
this.name = name; this.name = name;
this.access = access; this.access = access;
this.version = version; this.version = version;
} }
@Override @Override
public void visitMainClass(String mainClass) { public void visitMainClass(String mainClass) {
if (this.mainClass == 0) { // protect against several calls to visitMainClass if (this.mainClass == 0) { // protect against several calls to visitMainClass
cw.newUTF8("ModuleMainClass"); cw.newUTF8("ModuleMainClass");
attributeCount++; attributeCount++;
attributesSize += 8; attributesSize += 8;
} }
this.mainClass = cw.newClass(mainClass); this.mainClass = cw.newClass(mainClass);
} }
@Override @Override
public void visitPackage(String packaze) { public void visitPackage(String packaze) {
if (packages == null) { if (packages == null) {
// protect against several calls to visitPackage // protect against several calls to visitPackage
cw.newUTF8("ModulePackages"); cw.newUTF8("ModulePackages");
packages = new ByteVector(); packages = new ByteVector();
attributeCount++; attributeCount++;
attributesSize += 8; attributesSize += 8;
} }
packages.putShort(cw.newPackage(packaze)); packages.putShort(cw.newPackage(packaze));
packageCount++; packageCount++;
attributesSize += 2; attributesSize += 2;
} }
@Override @Override
public void visitRequire(String module, int access, String version) { public void visitRequire(String module, int access, String version) {
if (requires == null) { if (requires == null) {
requires = new ByteVector(); requires = new ByteVector();
} }
requires.putShort(cw.newModule(module)).putShort(access).putShort(version == null ? 0 : cw.newUTF8(version)); requires.putShort(cw.newModule(module)).putShort(access).putShort(version == null ? 0 : cw.newUTF8(version));
requireCount++; requireCount++;
size += 6; size += 6;
} }
@Override @Override
public void visitExport(String packaze, int access, String... modules) { public void visitExport(String packaze, int access, String... modules) {
if (exports == null) { if (exports == null) {
exports = new ByteVector(); exports = new ByteVector();
} }
exports.putShort(cw.newPackage(packaze)).putShort(access); exports.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) { if (modules == null) {
exports.putShort(0); exports.putShort(0);
size += 6; size += 6;
} else { } else {
exports.putShort(modules.length); exports.putShort(modules.length);
for (String module : modules) { for (String module : modules) {
exports.putShort(cw.newModule(module)); exports.putShort(cw.newModule(module));
} }
size += 6 + 2 * modules.length; size += 6 + 2 * modules.length;
} }
exportCount++; exportCount++;
} }
@Override @Override
public void visitOpen(String packaze, int access, String... modules) { public void visitOpen(String packaze, int access, String... modules) {
if (opens == null) { if (opens == null) {
opens = new ByteVector(); opens = new ByteVector();
} }
opens.putShort(cw.newPackage(packaze)).putShort(access); opens.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) { if (modules == null) {
opens.putShort(0); opens.putShort(0);
size += 6; size += 6;
} else { } else {
opens.putShort(modules.length); opens.putShort(modules.length);
for (String module : modules) { for (String module : modules) {
opens.putShort(cw.newModule(module)); opens.putShort(cw.newModule(module));
} }
size += 6 + 2 * modules.length; size += 6 + 2 * modules.length;
} }
openCount++; openCount++;
} }
@Override @Override
public void visitUse(String service) { public void visitUse(String service) {
if (uses == null) { if (uses == null) {
uses = new ByteVector(); uses = new ByteVector();
} }
uses.putShort(cw.newClass(service)); uses.putShort(cw.newClass(service));
useCount++; useCount++;
size += 2; size += 2;
} }
@Override @Override
public void visitProvide(String service, String... providers) { public void visitProvide(String service, String... providers) {
if (provides == null) { if (provides == null) {
provides = new ByteVector(); provides = new ByteVector();
} }
provides.putShort(cw.newClass(service)); provides.putShort(cw.newClass(service));
provides.putShort(providers.length); provides.putShort(providers.length);
for (String provider : providers) { for (String provider : providers) {
provides.putShort(cw.newClass(provider)); provides.putShort(cw.newClass(provider));
} }
provideCount++; provideCount++;
size += 4 + 2 * providers.length; size += 4 + 2 * providers.length;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
// empty // empty
} }
void putAttributes(ByteVector out) { void putAttributes(ByteVector out) {
if (mainClass != 0) { if (mainClass != 0) {
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass); out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
} }
if (packages != null) { if (packages != null) {
out.putShort(cw.newUTF8("ModulePackages")) out.putShort(cw.newUTF8("ModulePackages"))
.putInt(2 + 2 * packageCount) .putInt(2 + 2 * packageCount)
.putShort(packageCount) .putShort(packageCount)
.putByteArray(packages.data, 0, packages.length); .putByteArray(packages.data, 0, packages.length);
} }
} }
void put(ByteVector out) { void put(ByteVector out) {
out.putInt(size); out.putInt(size);
out.putShort(name).putShort(access).putShort(version); out.putShort(name).putShort(access).putShort(version);
out.putShort(requireCount); out.putShort(requireCount);
if (requires != null) { if (requires != null) {
out.putByteArray(requires.data, 0, requires.length); out.putByteArray(requires.data, 0, requires.length);
} }
out.putShort(exportCount); out.putShort(exportCount);
if (exports != null) { if (exports != null) {
out.putByteArray(exports.data, 0, exports.length); out.putByteArray(exports.data, 0, exports.length);
} }
out.putShort(openCount); out.putShort(openCount);
if (opens != null) { if (opens != null) {
out.putByteArray(opens.data, 0, opens.length); out.putByteArray(opens.data, 0, opens.length);
} }
out.putShort(useCount); out.putShort(useCount);
if (uses != null) { if (uses != null) {
out.putByteArray(uses.data, 0, uses.length); out.putByteArray(uses.data, 0, uses.length);
} }
out.putShort(provideCount); out.putShort(provideCount);
if (provides != null) { if (provides != null) {
out.putByteArray(provides.data, 0, provides.length); out.putByteArray(provides.data, 0, provides.length);
} }
} }
} }

View File

@@ -69,334 +69,334 @@ package org.redkale.asm;
*/ */
public interface Opcodes { public interface Opcodes {
// ASM API versions // ASM API versions
int ASM4 = 4 << 16 | 0 << 8; int ASM4 = 4 << 16 | 0 << 8;
int ASM5 = 5 << 16 | 0 << 8; int ASM5 = 5 << 16 | 0 << 8;
int ASM6 = 6 << 16 | 0 << 8; int ASM6 = 6 << 16 | 0 << 8;
// versions // versions
int V1_1 = 3 << 16 | 45; int V1_1 = 3 << 16 | 45;
int V1_2 = 0 << 16 | 46; int V1_2 = 0 << 16 | 46;
int V1_3 = 0 << 16 | 47; int V1_3 = 0 << 16 | 47;
int V1_4 = 0 << 16 | 48; int V1_4 = 0 << 16 | 48;
int V1_5 = 0 << 16 | 49; int V1_5 = 0 << 16 | 49;
int V1_6 = 0 << 16 | 50; int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51; int V1_7 = 0 << 16 | 51;
int V1_8 = 0 << 16 | 52; int V1_8 = 0 << 16 | 52;
int V9 = 0 << 16 | 53; int V9 = 0 << 16 | 53;
int V10 = 0 << 16 | 54; int V10 = 0 << 16 | 54;
int V11 = 0 << 16 | 55; int V11 = 0 << 16 | 55;
// access flags // access flags
int ACC_PUBLIC = 0x0001; // class, field, method int ACC_PUBLIC = 0x0001; // class, field, method
int ACC_PRIVATE = 0x0002; // class, field, method int ACC_PRIVATE = 0x0002; // class, field, method
int ACC_PROTECTED = 0x0004; // class, field, method int ACC_PROTECTED = 0x0004; // class, field, method
int ACC_STATIC = 0x0008; // field, method int ACC_STATIC = 0x0008; // field, method
int ACC_FINAL = 0x0010; // class, field, method, parameter int ACC_FINAL = 0x0010; // class, field, method, parameter
int ACC_SUPER = 0x0020; // class int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_OPEN = 0x0020; // module int ACC_OPEN = 0x0020; // module
int ACC_TRANSITIVE = 0x0020; // module requires int ACC_TRANSITIVE = 0x0020; // module requires
int ACC_VOLATILE = 0x0040; // field int ACC_VOLATILE = 0x0040; // field
int ACC_BRIDGE = 0x0040; // method int ACC_BRIDGE = 0x0040; // method
int ACC_STATIC_PHASE = 0x0040; // module requires int ACC_STATIC_PHASE = 0x0040; // module requires
int ACC_VARARGS = 0x0080; // method int ACC_VARARGS = 0x0080; // method
int ACC_TRANSIENT = 0x0080; // field int ACC_TRANSIENT = 0x0080; // field
int ACC_NATIVE = 0x0100; // method int ACC_NATIVE = 0x0100; // method
int ACC_INTERFACE = 0x0200; // class int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method int ACC_STRICT = 0x0800; // method
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner int ACC_ENUM = 0x4000; // class(?) field inner
int ACC_MANDATED = 0x8000; // parameter, module, module * int ACC_MANDATED = 0x8000; // parameter, module, module *
int ACC_MODULE = 0x8000; // class int ACC_MODULE = 0x8000; // class
// ASM specific pseudo access flags // ASM specific pseudo access flags
int ACC_DEPRECATED = 0x20000; // class, field, method int ACC_DEPRECATED = 0x20000; // class, field, method
// types for NEWARRAY // types for NEWARRAY
int T_BOOLEAN = 4; int T_BOOLEAN = 4;
int T_CHAR = 5; int T_CHAR = 5;
int T_FLOAT = 6; int T_FLOAT = 6;
int T_DOUBLE = 7; int T_DOUBLE = 7;
int T_BYTE = 8; int T_BYTE = 8;
int T_SHORT = 9; int T_SHORT = 9;
int T_INT = 10; int T_INT = 10;
int T_LONG = 11; int T_LONG = 11;
// tags for Handle // tags for Handle
int H_GETFIELD = 1; int H_GETFIELD = 1;
int H_GETSTATIC = 2; int H_GETSTATIC = 2;
int H_PUTFIELD = 3; int H_PUTFIELD = 3;
int H_PUTSTATIC = 4; int H_PUTSTATIC = 4;
int H_INVOKEVIRTUAL = 5; int H_INVOKEVIRTUAL = 5;
int H_INVOKESTATIC = 6; int H_INVOKESTATIC = 6;
int H_INVOKESPECIAL = 7; int H_INVOKESPECIAL = 7;
int H_NEWINVOKESPECIAL = 8; int H_NEWINVOKESPECIAL = 8;
int H_INVOKEINTERFACE = 9; int H_INVOKEINTERFACE = 9;
// stack map frame types // stack map frame types
/** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */ /** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
int F_NEW = -1; int F_NEW = -1;
/** Represents a compressed frame with complete frame data. */ /** Represents a compressed frame with complete frame data. */
int F_FULL = 0; int F_FULL = 0;
/** /**
* Represents a compressed frame where locals are the same as the locals in the previous frame, except that * Represents a compressed frame where locals are the same as the locals in the previous frame, except that
* additional 1-3 locals are defined, and with an empty stack. * additional 1-3 locals are defined, and with an empty stack.
*/ */
int F_APPEND = 1; int F_APPEND = 1;
/** /**
* Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last * Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last
* 1-3 locals are absent and with an empty stack. * 1-3 locals are absent and with an empty stack.
*/ */
int F_CHOP = 2; int F_CHOP = 2;
/** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */ /** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */
int F_SAME = 3; int F_SAME = 3;
/** /**
* Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the * Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the
* stack. * stack.
*/ */
int F_SAME1 = 4; int F_SAME1 = 4;
// Do not try to change the following code to use auto-boxing, // Do not try to change the following code to use auto-boxing,
// these values are compared by reference and not by value // these values are compared by reference and not by value
// The constructor of Integer was deprecated in 9 // The constructor of Integer was deprecated in 9
// but we are stuck with it by backward compatibility // but we are stuck with it by backward compatibility
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Integer TOP = new Integer(0); Integer TOP = new Integer(0);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Integer INTEGER = new Integer(1); Integer INTEGER = new Integer(1);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Integer FLOAT = new Integer(2); Integer FLOAT = new Integer(2);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Integer DOUBLE = new Integer(3); Integer DOUBLE = new Integer(3);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Integer LONG = new Integer(4); Integer LONG = new Integer(4);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Integer NULL = new Integer(5); Integer NULL = new Integer(5);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
Integer UNINITIALIZED_THIS = new Integer(6); Integer UNINITIALIZED_THIS = new Integer(6);
// opcodes // visit method (- = idem) // opcodes // visit method (- = idem)
int NOP = 0; // visitInsn int NOP = 0; // visitInsn
int ACONST_NULL = 1; // - int ACONST_NULL = 1; // -
int ICONST_M1 = 2; // - int ICONST_M1 = 2; // -
int ICONST_0 = 3; // - int ICONST_0 = 3; // -
int ICONST_1 = 4; // - int ICONST_1 = 4; // -
int ICONST_2 = 5; // - int ICONST_2 = 5; // -
int ICONST_3 = 6; // - int ICONST_3 = 6; // -
int ICONST_4 = 7; // - int ICONST_4 = 7; // -
int ICONST_5 = 8; // - int ICONST_5 = 8; // -
int LCONST_0 = 9; // - int LCONST_0 = 9; // -
int LCONST_1 = 10; // - int LCONST_1 = 10; // -
int FCONST_0 = 11; // - int FCONST_0 = 11; // -
int FCONST_1 = 12; // - int FCONST_1 = 12; // -
int FCONST_2 = 13; // - int FCONST_2 = 13; // -
int DCONST_0 = 14; // - int DCONST_0 = 14; // -
int DCONST_1 = 15; // - int DCONST_1 = 15; // -
int BIPUSH = 16; // visitIntInsn int BIPUSH = 16; // visitIntInsn
int SIPUSH = 17; // - int SIPUSH = 17; // -
int LDC = 18; // visitLdcInsn int LDC = 18; // visitLdcInsn
// int LDC_W = 19; // - // int LDC_W = 19; // -
// int LDC2_W = 20; // - // int LDC2_W = 20; // -
int ILOAD = 21; // visitVarInsn int ILOAD = 21; // visitVarInsn
int LLOAD = 22; // - int LLOAD = 22; // -
int FLOAD = 23; // - int FLOAD = 23; // -
int DLOAD = 24; // - int DLOAD = 24; // -
int ALOAD = 25; // - int ALOAD = 25; // -
// int ILOAD_0 = 26; // - // int ILOAD_0 = 26; // -
// int ILOAD_1 = 27; // - // int ILOAD_1 = 27; // -
// int ILOAD_2 = 28; // - // int ILOAD_2 = 28; // -
// int ILOAD_3 = 29; // - // int ILOAD_3 = 29; // -
// int LLOAD_0 = 30; // - // int LLOAD_0 = 30; // -
// int LLOAD_1 = 31; // - // int LLOAD_1 = 31; // -
// int LLOAD_2 = 32; // - // int LLOAD_2 = 32; // -
// int LLOAD_3 = 33; // - // int LLOAD_3 = 33; // -
// int FLOAD_0 = 34; // - // int FLOAD_0 = 34; // -
// int FLOAD_1 = 35; // - // int FLOAD_1 = 35; // -
// int FLOAD_2 = 36; // - // int FLOAD_2 = 36; // -
// int FLOAD_3 = 37; // - // int FLOAD_3 = 37; // -
// int DLOAD_0 = 38; // - // int DLOAD_0 = 38; // -
// int DLOAD_1 = 39; // - // int DLOAD_1 = 39; // -
// int DLOAD_2 = 40; // - // int DLOAD_2 = 40; // -
// int DLOAD_3 = 41; // - // int DLOAD_3 = 41; // -
// int ALOAD_0 = 42; // - // int ALOAD_0 = 42; // -
// int ALOAD_1 = 43; // - // int ALOAD_1 = 43; // -
// int ALOAD_2 = 44; // - // int ALOAD_2 = 44; // -
// int ALOAD_3 = 45; // - // int ALOAD_3 = 45; // -
int IALOAD = 46; // visitInsn int IALOAD = 46; // visitInsn
int LALOAD = 47; // - int LALOAD = 47; // -
int FALOAD = 48; // - int FALOAD = 48; // -
int DALOAD = 49; // - int DALOAD = 49; // -
int AALOAD = 50; // - int AALOAD = 50; // -
int BALOAD = 51; // - int BALOAD = 51; // -
int CALOAD = 52; // - int CALOAD = 52; // -
int SALOAD = 53; // - int SALOAD = 53; // -
int ISTORE = 54; // visitVarInsn int ISTORE = 54; // visitVarInsn
int LSTORE = 55; // - int LSTORE = 55; // -
int FSTORE = 56; // - int FSTORE = 56; // -
int DSTORE = 57; // - int DSTORE = 57; // -
int ASTORE = 58; // - int ASTORE = 58; // -
// int ISTORE_0 = 59; // - // int ISTORE_0 = 59; // -
// int ISTORE_1 = 60; // - // int ISTORE_1 = 60; // -
// int ISTORE_2 = 61; // - // int ISTORE_2 = 61; // -
// int ISTORE_3 = 62; // - // int ISTORE_3 = 62; // -
// int LSTORE_0 = 63; // - // int LSTORE_0 = 63; // -
// int LSTORE_1 = 64; // - // int LSTORE_1 = 64; // -
// int LSTORE_2 = 65; // - // int LSTORE_2 = 65; // -
// int LSTORE_3 = 66; // - // int LSTORE_3 = 66; // -
// int FSTORE_0 = 67; // - // int FSTORE_0 = 67; // -
// int FSTORE_1 = 68; // - // int FSTORE_1 = 68; // -
// int FSTORE_2 = 69; // - // int FSTORE_2 = 69; // -
// int FSTORE_3 = 70; // - // int FSTORE_3 = 70; // -
// int DSTORE_0 = 71; // - // int DSTORE_0 = 71; // -
// int DSTORE_1 = 72; // - // int DSTORE_1 = 72; // -
// int DSTORE_2 = 73; // - // int DSTORE_2 = 73; // -
// int DSTORE_3 = 74; // - // int DSTORE_3 = 74; // -
// int ASTORE_0 = 75; // - // int ASTORE_0 = 75; // -
// int ASTORE_1 = 76; // - // int ASTORE_1 = 76; // -
// int ASTORE_2 = 77; // - // int ASTORE_2 = 77; // -
// int ASTORE_3 = 78; // - // int ASTORE_3 = 78; // -
int IASTORE = 79; // visitInsn int IASTORE = 79; // visitInsn
int LASTORE = 80; // - int LASTORE = 80; // -
int FASTORE = 81; // - int FASTORE = 81; // -
int DASTORE = 82; // - int DASTORE = 82; // -
int AASTORE = 83; // - int AASTORE = 83; // -
int BASTORE = 84; // - int BASTORE = 84; // -
int CASTORE = 85; // - int CASTORE = 85; // -
int SASTORE = 86; // - int SASTORE = 86; // -
int POP = 87; // - int POP = 87; // -
int POP2 = 88; // - int POP2 = 88; // -
int DUP = 89; // - int DUP = 89; // -
int DUP_X1 = 90; // - int DUP_X1 = 90; // -
int DUP_X2 = 91; // - int DUP_X2 = 91; // -
int DUP2 = 92; // - int DUP2 = 92; // -
int DUP2_X1 = 93; // - int DUP2_X1 = 93; // -
int DUP2_X2 = 94; // - int DUP2_X2 = 94; // -
int SWAP = 95; // - int SWAP = 95; // -
int IADD = 96; // - int IADD = 96; // -
int LADD = 97; // - int LADD = 97; // -
int FADD = 98; // - int FADD = 98; // -
int DADD = 99; // - int DADD = 99; // -
int ISUB = 100; // - int ISUB = 100; // -
int LSUB = 101; // - int LSUB = 101; // -
int FSUB = 102; // - int FSUB = 102; // -
int DSUB = 103; // - int DSUB = 103; // -
int IMUL = 104; // - int IMUL = 104; // -
int LMUL = 105; // - int LMUL = 105; // -
int FMUL = 106; // - int FMUL = 106; // -
int DMUL = 107; // - int DMUL = 107; // -
int IDIV = 108; // - int IDIV = 108; // -
int LDIV = 109; // - int LDIV = 109; // -
int FDIV = 110; // - int FDIV = 110; // -
int DDIV = 111; // - int DDIV = 111; // -
int IREM = 112; // - int IREM = 112; // -
int LREM = 113; // - int LREM = 113; // -
int FREM = 114; // - int FREM = 114; // -
int DREM = 115; // - int DREM = 115; // -
int INEG = 116; // - int INEG = 116; // -
int LNEG = 117; // - int LNEG = 117; // -
int FNEG = 118; // - int FNEG = 118; // -
int DNEG = 119; // - int DNEG = 119; // -
int ISHL = 120; // - int ISHL = 120; // -
int LSHL = 121; // - int LSHL = 121; // -
int ISHR = 122; // - int ISHR = 122; // -
int LSHR = 123; // - int LSHR = 123; // -
int IUSHR = 124; // - int IUSHR = 124; // -
int LUSHR = 125; // - int LUSHR = 125; // -
int IAND = 126; // - int IAND = 126; // -
int LAND = 127; // - int LAND = 127; // -
int IOR = 128; // - int IOR = 128; // -
int LOR = 129; // - int LOR = 129; // -
int IXOR = 130; // - int IXOR = 130; // -
int LXOR = 131; // - int LXOR = 131; // -
int IINC = 132; // visitIincInsn int IINC = 132; // visitIincInsn
int I2L = 133; // visitInsn int I2L = 133; // visitInsn
int I2F = 134; // - int I2F = 134; // -
int I2D = 135; // - int I2D = 135; // -
int L2I = 136; // - int L2I = 136; // -
int L2F = 137; // - int L2F = 137; // -
int L2D = 138; // - int L2D = 138; // -
int F2I = 139; // - int F2I = 139; // -
int F2L = 140; // - int F2L = 140; // -
int F2D = 141; // - int F2D = 141; // -
int D2I = 142; // - int D2I = 142; // -
int D2L = 143; // - int D2L = 143; // -
int D2F = 144; // - int D2F = 144; // -
int I2B = 145; // - int I2B = 145; // -
int I2C = 146; // - int I2C = 146; // -
int I2S = 147; // - int I2S = 147; // -
int LCMP = 148; // - int LCMP = 148; // -
int FCMPL = 149; // - int FCMPL = 149; // -
int FCMPG = 150; // - int FCMPG = 150; // -
int DCMPL = 151; // - int DCMPL = 151; // -
int DCMPG = 152; // - int DCMPG = 152; // -
int IFEQ = 153; // visitJumpInsn int IFEQ = 153; // visitJumpInsn
int IFNE = 154; // - int IFNE = 154; // -
int IFLT = 155; // - int IFLT = 155; // -
int IFGE = 156; // - int IFGE = 156; // -
int IFGT = 157; // - int IFGT = 157; // -
int IFLE = 158; // - int IFLE = 158; // -
int IF_ICMPEQ = 159; // - int IF_ICMPEQ = 159; // -
int IF_ICMPNE = 160; // - int IF_ICMPNE = 160; // -
int IF_ICMPLT = 161; // - int IF_ICMPLT = 161; // -
int IF_ICMPGE = 162; // - int IF_ICMPGE = 162; // -
int IF_ICMPGT = 163; // - int IF_ICMPGT = 163; // -
int IF_ICMPLE = 164; // - int IF_ICMPLE = 164; // -
int IF_ACMPEQ = 165; // - int IF_ACMPEQ = 165; // -
int IF_ACMPNE = 166; // - int IF_ACMPNE = 166; // -
int GOTO = 167; // - int GOTO = 167; // -
int JSR = 168; // - int JSR = 168; // -
int RET = 169; // visitVarInsn int RET = 169; // visitVarInsn
int TABLESWITCH = 170; // visiTableSwitchInsn int TABLESWITCH = 170; // visiTableSwitchInsn
int LOOKUPSWITCH = 171; // visitLookupSwitch int LOOKUPSWITCH = 171; // visitLookupSwitch
int IRETURN = 172; // visitInsn int IRETURN = 172; // visitInsn
int LRETURN = 173; // - int LRETURN = 173; // -
int FRETURN = 174; // - int FRETURN = 174; // -
int DRETURN = 175; // - int DRETURN = 175; // -
int ARETURN = 176; // - int ARETURN = 176; // -
int RETURN = 177; // - int RETURN = 177; // -
int GETSTATIC = 178; // visitFieldInsn int GETSTATIC = 178; // visitFieldInsn
int PUTSTATIC = 179; // - int PUTSTATIC = 179; // -
int GETFIELD = 180; // - int GETFIELD = 180; // -
int PUTFIELD = 181; // - int PUTFIELD = 181; // -
int INVOKEVIRTUAL = 182; // visitMethodInsn int INVOKEVIRTUAL = 182; // visitMethodInsn
int INVOKESPECIAL = 183; // - int INVOKESPECIAL = 183; // -
int INVOKESTATIC = 184; // - int INVOKESTATIC = 184; // -
int INVOKEINTERFACE = 185; // - int INVOKEINTERFACE = 185; // -
int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
int NEW = 187; // visitTypeInsn int NEW = 187; // visitTypeInsn
int NEWARRAY = 188; // visitIntInsn int NEWARRAY = 188; // visitIntInsn
int ANEWARRAY = 189; // visitTypeInsn int ANEWARRAY = 189; // visitTypeInsn
int ARRAYLENGTH = 190; // visitInsn int ARRAYLENGTH = 190; // visitInsn
int ATHROW = 191; // - int ATHROW = 191; // -
int CHECKCAST = 192; // visitTypeInsn int CHECKCAST = 192; // visitTypeInsn
int INSTANCEOF = 193; // - int INSTANCEOF = 193; // -
int MONITORENTER = 194; // visitInsn int MONITORENTER = 194; // visitInsn
int MONITOREXIT = 195; // - int MONITOREXIT = 195; // -
// int WIDE = 196; // NOT VISITED // int WIDE = 196; // NOT VISITED
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
int IFNULL = 198; // visitJumpInsn int IFNULL = 198; // visitJumpInsn
int IFNONNULL = 199; // - int IFNONNULL = 199; // -
// int GOTO_W = 200; // - // int GOTO_W = 200; // -
// int JSR_W = 201; // - // int JSR_W = 201; // -
} }

File diff suppressed because it is too large Load Diff

View File

@@ -66,130 +66,130 @@ package org.redkale.asm;
*/ */
public class TypePath { public class TypePath {
/** A type path step that steps into the element type of an array type. See {@link #getStep getStep}. */ /** A type path step that steps into the element type of an array type. See {@link #getStep getStep}. */
public static final int ARRAY_ELEMENT = 0; public static final int ARRAY_ELEMENT = 0;
/** A type path step that steps into the nested type of a class type. See {@link #getStep getStep}. */ /** A type path step that steps into the nested type of a class type. See {@link #getStep getStep}. */
public static final int INNER_TYPE = 1; public static final int INNER_TYPE = 1;
/** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */ /** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */
public static final int WILDCARD_BOUND = 2; public static final int WILDCARD_BOUND = 2;
/** A type path step that steps into a type argument of a generic type. See {@link #getStep getStep}. */ /** A type path step that steps into a type argument of a generic type. See {@link #getStep getStep}. */
public static final int TYPE_ARGUMENT = 3; public static final int TYPE_ARGUMENT = 3;
/** The byte array where the path is stored, in Java class file format. */ /** The byte array where the path is stored, in Java class file format. */
byte[] b; byte[] b;
/** The offset of the first byte of the type path in 'b'. */ /** The offset of the first byte of the type path in 'b'. */
int offset; int offset;
/** /**
* Creates a new type path. * Creates a new type path.
* *
* @param b the byte array containing the type path in Java class file format. * @param b the byte array containing the type path in Java class file format.
* @param offset the offset of the first byte of the type path in 'b'. * @param offset the offset of the first byte of the type path in 'b'.
*/ */
TypePath(byte[] b, int offset) { TypePath(byte[] b, int offset) {
this.b = b; this.b = b;
this.offset = offset; this.offset = offset;
} }
/** /**
* Returns the length of this path. * Returns the length of this path.
* *
* @return the length of this path. * @return the length of this path.
*/ */
public int getLength() { public int getLength() {
return b[offset]; return b[offset];
} }
/** /**
* Returns the value of the given step of this path. * Returns the value of the given step of this path.
* *
* @param index an index between 0 and {@link #getLength()}, exclusive. * @param index an index between 0 and {@link #getLength()}, exclusive.
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND
* WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. * WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
*/ */
public int getStep(int index) { public int getStep(int index) {
return b[offset + 2 * index + 1]; return b[offset + 2 * index + 1];
} }
/** /**
* Returns the index of the type argument that the given step is stepping into. This method should only be used for * Returns the index of the type argument that the given step is stepping into. This method should only be used for
* steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. * steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
* *
* @param index an index between 0 and {@link #getLength()}, exclusive. * @param index an index between 0 and {@link #getLength()}, exclusive.
* @return the index of the type argument that the given step is stepping into. * @return the index of the type argument that the given step is stepping into.
*/ */
public int getStepArgument(int index) { public int getStepArgument(int index) {
return b[offset + 2 * index + 2]; return b[offset + 2 * index + 2];
} }
/** /**
* Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object. * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object.
* *
* @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty. * @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty.
* @return the corresponding TypePath object, or null if the path is empty. * @return the corresponding TypePath object, or null if the path is empty.
*/ */
public static TypePath fromString(final String typePath) { public static TypePath fromString(final String typePath) {
if (typePath == null || typePath.isEmpty()) { if (typePath == null || typePath.isEmpty()) {
return null; return null;
} }
int n = typePath.length(); int n = typePath.length();
ByteVector out = new ByteVector(n); ByteVector out = new ByteVector(n);
out.putByte(0); out.putByte(0);
for (int i = 0; i < n; ) { for (int i = 0; i < n; ) {
char c = typePath.charAt(i++); char c = typePath.charAt(i++);
if (c == '[') { if (c == '[') {
out.put11(ARRAY_ELEMENT, 0); out.put11(ARRAY_ELEMENT, 0);
} else if (c == '.') { } else if (c == '.') {
out.put11(INNER_TYPE, 0); out.put11(INNER_TYPE, 0);
} else if (c == '*') { } else if (c == '*') {
out.put11(WILDCARD_BOUND, 0); out.put11(WILDCARD_BOUND, 0);
} else if (c >= '0' && c <= '9') { } else if (c >= '0' && c <= '9') {
int typeArg = c - '0'; int typeArg = c - '0';
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') { while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
typeArg = typeArg * 10 + c - '0'; typeArg = typeArg * 10 + c - '0';
i += 1; i += 1;
} }
if (i < n && typePath.charAt(i) == ';') { if (i < n && typePath.charAt(i) == ';') {
i += 1; i += 1;
} }
out.put11(TYPE_ARGUMENT, typeArg); out.put11(TYPE_ARGUMENT, typeArg);
} }
} }
out.data[0] = (byte) (out.length / 2); out.data[0] = (byte) (out.length / 2);
return new TypePath(out.data, 0); return new TypePath(out.data, 0);
} }
/** /**
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented * Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented
* with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*' * with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*'
* and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'. * and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
*/ */
@Override @Override
public String toString() { public String toString() {
int length = getLength(); int length = getLength();
StringBuilder result = new StringBuilder(length * 2); StringBuilder result = new StringBuilder(length * 2);
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
switch (getStep(i)) { switch (getStep(i)) {
case ARRAY_ELEMENT: case ARRAY_ELEMENT:
result.append('['); result.append('[');
break; break;
case INNER_TYPE: case INNER_TYPE:
result.append('.'); result.append('.');
break; break;
case WILDCARD_BOUND: case WILDCARD_BOUND:
result.append('*'); result.append('*');
break; break;
case TYPE_ARGUMENT: case TYPE_ARGUMENT:
result.append(getStepArgument(i)).append(';'); result.append(getStepArgument(i)).append(';');
break; break;
default: default:
result.append('_'); result.append('_');
} }
} }
return result.toString(); return result.toString();
} }
} }

View File

@@ -68,335 +68,335 @@ package org.redkale.asm;
*/ */
public class TypeReference { public class TypeReference {
/** The sort of type references that target a type parameter of a generic class. See {@link #getSort getSort}. */ /** The sort of type references that target a type parameter of a generic class. See {@link #getSort getSort}. */
public static final int CLASS_TYPE_PARAMETER = 0x00; public static final int CLASS_TYPE_PARAMETER = 0x00;
/** The sort of type references that target a type parameter of a generic method. See {@link #getSort getSort}. */ /** The sort of type references that target a type parameter of a generic method. See {@link #getSort getSort}. */
public static final int METHOD_TYPE_PARAMETER = 0x01; public static final int METHOD_TYPE_PARAMETER = 0x01;
/** /**
* The sort of type references that target the super class of a class or one of the interfaces it implements. See * The sort of type references that target the super class of a class or one of the interfaces it implements. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int CLASS_EXTENDS = 0x10; public static final int CLASS_EXTENDS = 0x10;
/** /**
* The sort of type references that target a bound of a type parameter of a generic class. See {@link #getSort * The sort of type references that target a bound of a type parameter of a generic class. See {@link #getSort
* getSort}. * getSort}.
*/ */
public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11;
/** /**
* The sort of type references that target a bound of a type parameter of a generic method. See {@link #getSort * The sort of type references that target a bound of a type parameter of a generic method. See {@link #getSort
* getSort}. * getSort}.
*/ */
public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
/** The sort of type references that target the type of a field. See {@link #getSort getSort}. */ /** The sort of type references that target the type of a field. See {@link #getSort getSort}. */
public static final int FIELD = 0x13; public static final int FIELD = 0x13;
/** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */ /** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */
public static final int METHOD_RETURN = 0x14; public static final int METHOD_RETURN = 0x14;
/** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */ /** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */
public static final int METHOD_RECEIVER = 0x15; public static final int METHOD_RECEIVER = 0x15;
/** /**
* The sort of type references that target the type of a formal parameter of a method. See {@link #getSort getSort}. * The sort of type references that target the type of a formal parameter of a method. See {@link #getSort getSort}.
*/ */
public static final int METHOD_FORMAL_PARAMETER = 0x16; public static final int METHOD_FORMAL_PARAMETER = 0x16;
/** /**
* The sort of type references that target the type of an exception declared in the throws clause of a method. See * The sort of type references that target the type of an exception declared in the throws clause of a method. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int THROWS = 0x17; public static final int THROWS = 0x17;
/** /**
* The sort of type references that target the type of a local variable in a method. See {@link #getSort getSort}. * The sort of type references that target the type of a local variable in a method. See {@link #getSort getSort}.
*/ */
public static final int LOCAL_VARIABLE = 0x40; public static final int LOCAL_VARIABLE = 0x40;
/** /**
* The sort of type references that target the type of a resource variable in a method. See {@link #getSort * The sort of type references that target the type of a resource variable in a method. See {@link #getSort
* getSort}. * getSort}.
*/ */
public static final int RESOURCE_VARIABLE = 0x41; public static final int RESOURCE_VARIABLE = 0x41;
/** /**
* The sort of type references that target the type of the exception of a 'catch' clause in a method. See * The sort of type references that target the type of the exception of a 'catch' clause in a method. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int EXCEPTION_PARAMETER = 0x42; public static final int EXCEPTION_PARAMETER = 0x42;
/** /**
* The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort * The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort
* getSort}. * getSort}.
*/ */
public static final int INSTANCEOF = 0x43; public static final int INSTANCEOF = 0x43;
/** /**
* The sort of type references that target the type of the object created by a 'new' instruction. See * The sort of type references that target the type of the object created by a 'new' instruction. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int NEW = 0x44; public static final int NEW = 0x44;
/** /**
* The sort of type references that target the receiver type of a constructor reference. See {@link #getSort * The sort of type references that target the receiver type of a constructor reference. See {@link #getSort
* getSort}. * getSort}.
*/ */
public static final int CONSTRUCTOR_REFERENCE = 0x45; public static final int CONSTRUCTOR_REFERENCE = 0x45;
/** /**
* The sort of type references that target the receiver type of a method reference. See {@link #getSort getSort}. * The sort of type references that target the receiver type of a method reference. See {@link #getSort getSort}.
*/ */
public static final int METHOD_REFERENCE = 0x46; public static final int METHOD_REFERENCE = 0x46;
/** /**
* The sort of type references that target the type declared in an explicit or implicit cast instruction. See * The sort of type references that target the type declared in an explicit or implicit cast instruction. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int CAST = 0x47; public static final int CAST = 0x47;
/** /**
* The sort of type references that target a type parameter of a generic constructor in a constructor call. See * The sort of type references that target a type parameter of a generic constructor in a constructor call. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
/** /**
* The sort of type references that target a type parameter of a generic method in a method call. See * The sort of type references that target a type parameter of a generic method in a method call. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
/** /**
* The sort of type references that target a type parameter of a generic constructor in a constructor reference. See * The sort of type references that target a type parameter of a generic constructor in a constructor reference. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
/** /**
* The sort of type references that target a type parameter of a generic method in a method reference. See * The sort of type references that target a type parameter of a generic method in a method reference. See
* {@link #getSort getSort}. * {@link #getSort getSort}.
*/ */
public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
/** The type reference value in Java class file format. */ /** The type reference value in Java class file format. */
private int value; private int value;
/** /**
* Creates a new TypeReference. * Creates a new TypeReference.
* *
* @param typeRef the int encoded value of the type reference, as received in a visit method related to type * @param typeRef the int encoded value of the type reference, as received in a visit method related to type
* annotations, like visitTypeAnnotation. * annotations, like visitTypeAnnotation.
*/ */
public TypeReference(int typeRef) { public TypeReference(int typeRef) {
this.value = typeRef; this.value = typeRef;
} }
/** /**
* Returns a type reference of the given sort. * Returns a type reference of the given sort.
* *
* @param sort {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER}, * @param sort {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #INSTANCEOF * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #INSTANCEOF
* INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or * INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
* {@link #METHOD_REFERENCE METHOD_REFERENCE}. * {@link #METHOD_REFERENCE METHOD_REFERENCE}.
* @return a type reference of the given sort. * @return a type reference of the given sort.
*/ */
public static TypeReference newTypeReference(int sort) { public static TypeReference newTypeReference(int sort) {
return new TypeReference(sort << 24); return new TypeReference(sort << 24);
} }
/** /**
* Returns a reference to a type parameter of a generic class or method. * Returns a reference to a type parameter of a generic class or method.
* *
* @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER * @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
* METHOD_TYPE_PARAMETER}. * METHOD_TYPE_PARAMETER}.
* @param paramIndex the type parameter index. * @param paramIndex the type parameter index.
* @return a reference to the given generic class or method type parameter. * @return a reference to the given generic class or method type parameter.
*/ */
public static TypeReference newTypeParameterReference(int sort, int paramIndex) { public static TypeReference newTypeParameterReference(int sort, int paramIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16)); return new TypeReference((sort << 24) | (paramIndex << 16));
} }
/** /**
* Returns a reference to a type parameter bound of a generic class or method. * Returns a reference to a type parameter bound of a generic class or method.
* *
* @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER * @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
* METHOD_TYPE_PARAMETER}. * METHOD_TYPE_PARAMETER}.
* @param paramIndex the type parameter index. * @param paramIndex the type parameter index.
* @param boundIndex the type bound index within the above type parameters. * @param boundIndex the type bound index within the above type parameters.
* @return a reference to the given generic class or method type parameter bound. * @return a reference to the given generic class or method type parameter bound.
*/ */
public static TypeReference newTypeParameterBoundReference(int sort, int paramIndex, int boundIndex) { public static TypeReference newTypeParameterBoundReference(int sort, int paramIndex, int boundIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8)); return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
} }
/** /**
* Returns a reference to the super class or to an interface of the 'implements' clause of a class. * Returns a reference to the super class or to an interface of the 'implements' clause of a class.
* *
* @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to reference the super * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to reference the super
* class of the class. * class of the class.
* @return a reference to the given super type of a class. * @return a reference to the given super type of a class.
*/ */
public static TypeReference newSuperTypeReference(int itfIndex) { public static TypeReference newSuperTypeReference(int itfIndex) {
itfIndex &= 0xFFFF; itfIndex &= 0xFFFF;
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8)); return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
} }
/** /**
* Returns a reference to the type of a formal parameter of a method. * Returns a reference to the type of a formal parameter of a method.
* *
* @param paramIndex the formal parameter index. * @param paramIndex the formal parameter index.
* @return a reference to the type of the given method formal parameter. * @return a reference to the type of the given method formal parameter.
*/ */
public static TypeReference newFormalParameterReference(int paramIndex) { public static TypeReference newFormalParameterReference(int paramIndex) {
return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16)); return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
} }
/** /**
* Returns a reference to the type of an exception, in a 'throws' clause of a method. * Returns a reference to the type of an exception, in a 'throws' clause of a method.
* *
* @param exceptionIndex the index of an exception in a 'throws' clause of a method. * @param exceptionIndex the index of an exception in a 'throws' clause of a method.
* @return a reference to the type of the given exception. * @return a reference to the type of the given exception.
*/ */
public static TypeReference newExceptionReference(int exceptionIndex) { public static TypeReference newExceptionReference(int exceptionIndex) {
return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
} }
/** /**
* Returns a reference to the type of the exception declared in a 'catch' clause of a method. * Returns a reference to the type of the exception declared in a 'catch' clause of a method.
* *
* @param tryCatchBlockIndex the index of a try catch block (using the order in which they are visited with * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are visited with
* visitTryCatchBlock). * visitTryCatchBlock).
* @return a reference to the type of the given exception. * @return a reference to the type of the given exception.
*/ */
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) { public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8)); return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
} }
/** /**
* Returns a reference to the type of a type argument in a constructor or method call or reference. * Returns a reference to the type of a type argument in a constructor or method call or reference.
* *
* @param sort {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT * @param sort {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}. * METHOD_REFERENCE_TYPE_ARGUMENT}.
* @param argIndex the type argument index. * @param argIndex the type argument index.
* @return a reference to the type of the given type argument. * @return a reference to the type of the given type argument.
*/ */
public static TypeReference newTypeArgumentReference(int sort, int argIndex) { public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
return new TypeReference((sort << 24) | argIndex); return new TypeReference((sort << 24) | argIndex);
} }
/** /**
* Returns the sort of this type reference. * Returns the sort of this type reference.
* *
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_EXTENDS CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}, * {@link #CLASS_EXTENDS CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, {@link #FIELD FIELD}, {@link #METHOD_RETURN * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, {@link #FIELD FIELD}, {@link #METHOD_RETURN
* METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER}, {@link #METHOD_FORMAL_PARAMETER * METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER}, {@link #METHOD_FORMAL_PARAMETER
* METHOD_FORMAL_PARAMETER}, {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, * METHOD_FORMAL_PARAMETER}, {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER}, * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT * METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}. * METHOD_REFERENCE_TYPE_ARGUMENT}.
*/ */
public int getSort() { public int getSort() {
return value >>> 24; return value >>> 24;
} }
/** /**
* Returns the index of the type parameter referenced by this type reference. This method must only be used for type * Returns the index of the type parameter referenced by this type reference. This method must only be used for type
* references whose sort is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER * references whose sort is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER
* METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or * METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
* *
* @return a type parameter index. * @return a type parameter index.
*/ */
public int getTypeParameterIndex() { public int getTypeParameterIndex() {
return (value & 0x00FF0000) >> 16; return (value & 0x00FF0000) >> 16;
} }
/** /**
* Returns the index of the type parameter bound, within the type parameter {@link #getTypeParameterIndex}, * Returns the index of the type parameter bound, within the type parameter {@link #getTypeParameterIndex},
* referenced by this type reference. This method must only be used for type references whose sort is * referenced by this type reference. This method must only be used for type references whose sort is
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or {@link #METHOD_TYPE_PARAMETER_BOUND * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or {@link #METHOD_TYPE_PARAMETER_BOUND
* METHOD_TYPE_PARAMETER_BOUND}. * METHOD_TYPE_PARAMETER_BOUND}.
* *
* @return a type parameter bound index. * @return a type parameter bound index.
*/ */
public int getTypeParameterBoundIndex() { public int getTypeParameterBoundIndex() {
return (value & 0x0000FF00) >> 8; return (value & 0x0000FF00) >> 8;
} }
/** /**
* Returns the index of the "super type" of a class that is referenced by this type reference. This method must only * Returns the index of the "super type" of a class that is referenced by this type reference. This method must only
* be used for type references whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}. * be used for type references whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
* *
* @return the index of an interface in the 'implements' clause of a class, or -1 if this type reference references * @return the index of an interface in the 'implements' clause of a class, or -1 if this type reference references
* the type of the super class. * the type of the super class.
*/ */
public int getSuperTypeIndex() { public int getSuperTypeIndex() {
return (short) ((value & 0x00FFFF00) >> 8); return (short) ((value & 0x00FFFF00) >> 8);
} }
/** /**
* Returns the index of the formal parameter whose type is referenced by this type reference. This method must only * Returns the index of the formal parameter whose type is referenced by this type reference. This method must only
* be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}. * be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
* *
* @return a formal parameter index. * @return a formal parameter index.
*/ */
public int getFormalParameterIndex() { public int getFormalParameterIndex() {
return (value & 0x00FF0000) >> 16; return (value & 0x00FF0000) >> 16;
} }
/** /**
* Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced by this type * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced by this type
* reference. This method must only be used for type references whose sort is {@link #THROWS THROWS}. * reference. This method must only be used for type references whose sort is {@link #THROWS THROWS}.
* *
* @return the index of an exception in the 'throws' clause of a method. * @return the index of an exception in the 'throws' clause of a method.
*/ */
public int getExceptionIndex() { public int getExceptionIndex() {
return (value & 0x00FFFF00) >> 8; return (value & 0x00FFFF00) >> 8;
} }
/** /**
* Returns the index of the try catch block (using the order in which they are visited with visitTryCatchBlock), * Returns the index of the try catch block (using the order in which they are visited with visitTryCatchBlock),
* whose 'catch' type is referenced by this type reference. This method must only be used for type references whose * whose 'catch' type is referenced by this type reference. This method must only be used for type references whose
* sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} . * sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
* *
* @return the index of an exception in the 'throws' clause of a method. * @return the index of an exception in the 'throws' clause of a method.
*/ */
public int getTryCatchBlockIndex() { public int getTryCatchBlockIndex() {
return (value & 0x00FFFF00) >> 8; return (value & 0x00FFFF00) >> 8;
} }
/** /**
* Returns the index of the type argument referenced by this type reference. This method must only be used for type * Returns the index of the type argument referenced by this type reference. This method must only be used for type
* references whose sort is {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT * references whose sort is {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
* *
* @return a type parameter index. * @return a type parameter index.
*/ */
public int getTypeArgumentIndex() { public int getTypeArgumentIndex() {
return value & 0xFF; return value & 0xFF;
} }
/** /**
* Returns the int encoded value of this type reference, suitable for use in visit methods related to type * Returns the int encoded value of this type reference, suitable for use in visit methods related to type
* annotations, like visitTypeAnnotation. * annotations, like visitTypeAnnotation.
* *
* @return the int encoded value of this type reference. * @return the int encoded value of this type reference.
*/ */
public int getValue() { public int getValue() {
return value; return value;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -38,457 +38,457 @@ import org.redkale.util.Utility;
*/ */
class AppConfig { class AppConfig {
/** /**
* 当前进程的配置文件, 类型String、URI、File、Path <br> * 当前进程的配置文件, 类型String、URI、File、Path <br>
* 一般命名为: application.xml、application.onlyLogProps 若配置文件不是本地文件, 则File、Path类型的值为null * 一般命名为: application.xml、application.onlyLogProps 若配置文件不是本地文件, 则File、Path类型的值为null
*/ */
static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE"; static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE";
// 是否用于main方法运行 // 是否用于main方法运行
final boolean singletonMode; final boolean singletonMode;
// 是否用于编译模式运行 // 是否用于编译模式运行
final boolean compileMode; final boolean compileMode;
// application.xml原始配置信息 // application.xml原始配置信息
AnyValue config; AnyValue config;
// 是否从/META-INF中读取配置 // 是否从/META-INF中读取配置
boolean configFromCache; boolean configFromCache;
// 本进程节点ID // 本进程节点ID
String nodeid; String nodeid;
// 本进程节点ID // 本进程节点ID
String name; String name;
// 本地IP地址 // 本地IP地址
InetSocketAddress localAddress; InetSocketAddress localAddress;
// 进程根目录 // 进程根目录
File home; File home;
// 配置文件目录 // 配置文件目录
File confFile; File confFile;
// 配置文件目录 // 配置文件目录
URI confDir; URI confDir;
// 根ClassLoader // 根ClassLoader
RedkaleClassLoader classLoader; RedkaleClassLoader classLoader;
// Server根ClassLoader // Server根ClassLoader
RedkaleClassLoader serverClassLoader; RedkaleClassLoader serverClassLoader;
// 本地文件日志配置项 // 本地文件日志配置项
final Properties locaLogProperties = new Properties(); final Properties locaLogProperties = new Properties();
// 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的 // 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的
final Properties localEnvProperties = new Properties(); final Properties localEnvProperties = new Properties();
public AppConfig(boolean singletonMode, boolean compileMode) { public AppConfig(boolean singletonMode, boolean compileMode) {
this.singletonMode = singletonMode; this.singletonMode = singletonMode;
this.compileMode = compileMode; this.compileMode = compileMode;
} }
public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException { public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException {
AppConfig rs = new AppConfig(singletonMode, compileMode); AppConfig rs = new AppConfig(singletonMode, compileMode);
rs.init(loadAppConfig()); rs.init(loadAppConfig());
return rs; return rs;
} }
private void init(AnyValue conf) { private void init(AnyValue conf) {
this.config = conf; this.config = conf;
this.name = checkName(config.getValue("name", "")); this.name = checkName(config.getValue("name", ""));
this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime())))); this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime()))));
this.configFromCache = "true".equals(config.getValue("[config-from-cache]")); this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
// 初始化classLoader、serverClassLoader // 初始化classLoader、serverClassLoader
this.initClassLoader(); this.initClassLoader();
// 初始化home、confDir、localAddress等信息 // 初始化home、confDir、localAddress等信息
this.initAppHome(); this.initAppHome();
// 读取本地参数配置 // 读取本地参数配置
this.initLocalProperties(); this.initLocalProperties();
// 读取本地日志配置 // 读取本地日志配置
this.initLogProperties(); this.initLogProperties();
// 读取本地数据库配置 // 读取本地数据库配置
this.initSourceProperties(); this.initSourceProperties();
} }
/** 初始化classLoader、serverClassLoader */ /** 初始化classLoader、serverClassLoader */
private void initClassLoader() { private void initClassLoader() {
ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader(); ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader();
if (currClassLoader instanceof RedkaleClassLoader) { if (currClassLoader instanceof RedkaleClassLoader) {
this.classLoader = (RedkaleClassLoader) currClassLoader; this.classLoader = (RedkaleClassLoader) currClassLoader;
} else { } else {
Set<String> cacheClasses = null; Set<String> cacheClasses = null;
if (!singletonMode && !compileMode) { if (!singletonMode && !compileMode) {
try { try {
InputStream in = InputStream in =
Application.class.getResourceAsStream(RedkaleClassLoader.RESOURCE_CACHE_CLASSES_PATH); Application.class.getResourceAsStream(RedkaleClassLoader.RESOURCE_CACHE_CLASSES_PATH);
if (in != null) { if (in != null) {
BufferedReader reader = BufferedReader reader =
new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024); new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024);
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
reader.lines().forEach(list::add); reader.lines().forEach(list::add);
Collections.sort(list); Collections.sort(list);
if (!list.isEmpty()) { if (!list.isEmpty()) {
cacheClasses = new LinkedHashSet<>(list); cacheClasses = new LinkedHashSet<>(list);
} }
in.close(); in.close();
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
} }
if (cacheClasses == null) { if (cacheClasses == null) {
this.classLoader = new RedkaleClassLoader(currClassLoader); this.classLoader = new RedkaleClassLoader(currClassLoader);
} else { } else {
this.classLoader = new RedkaleClassLoader.RedkaleCacheClassLoader(currClassLoader, cacheClasses); this.classLoader = new RedkaleClassLoader.RedkaleCacheClassLoader(currClassLoader, cacheClasses);
} }
Thread.currentThread().setContextClassLoader(this.classLoader); Thread.currentThread().setContextClassLoader(this.classLoader);
} }
if (compileMode || this.classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader) { if (compileMode || this.classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader) {
this.serverClassLoader = this.classLoader; this.serverClassLoader = this.classLoader;
} else { } else {
this.serverClassLoader = new RedkaleClassLoader(this.classLoader); this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
} }
} }
/** 初始化home、confDir、localAddress等信息 */ /** 初始化home、confDir、localAddress等信息 */
private void initAppHome() { private void initAppHome() {
final File root = new File(System.getProperty(RESNAME_APP_HOME, "")); final File root = new File(System.getProperty(RESNAME_APP_HOME, ""));
final String rootPath = getCanonicalPath(root); final String rootPath = getCanonicalPath(root);
this.home = new File(rootPath); this.home = new File(rootPath);
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
if (confDir.contains("://") if (confDir.contains("://")
|| confDir.startsWith("file:") || confDir.startsWith("file:")
|| confDir.startsWith("resource:") || confDir.startsWith("resource:")
|| confDir.contains("!")) { // graalvm native-image startwith resource:META-INF || confDir.contains("!")) { // graalvm native-image startwith resource:META-INF
this.confDir = URI.create(confDir); this.confDir = URI.create(confDir);
if (confDir.startsWith("file:")) { if (confDir.startsWith("file:")) {
this.confFile = getCanonicalFile(new File(this.confDir.getPath())); this.confFile = getCanonicalFile(new File(this.confDir.getPath()));
} }
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) { } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) {
this.confFile = getCanonicalFile(new File(confDir)); this.confFile = getCanonicalFile(new File(confDir));
this.confDir = confFile.toURI(); this.confDir = confFile.toURI();
} else { } else {
this.confFile = new File(getCanonicalPath(new File(this.home, confDir))); this.confFile = new File(getCanonicalPath(new File(this.home, confDir)));
this.confDir = confFile.toURI(); this.confDir = confFile.toURI();
} }
String localaddr = config.getValue("address", "").trim(); String localaddr = config.getValue("address", "").trim();
InetAddress addr = localaddr.isEmpty() InetAddress addr = localaddr.isEmpty()
? Utility.localInetAddress() ? Utility.localInetAddress()
: new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress(); : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
this.localAddress = new InetSocketAddress(addr, config.getIntValue("port")); this.localAddress = new InetSocketAddress(addr, config.getIntValue("port"));
} }
/** 读取本地参数配置 */ /** 读取本地参数配置 */
private void initLocalProperties() { private void initLocalProperties() {
// 环境变量的优先级最高 // 环境变量的优先级最高
System.getProperties().forEach((k, v) -> { System.getProperties().forEach((k, v) -> {
if (k.toString().startsWith("redkale.")) { if (k.toString().startsWith("redkale.")) {
localEnvProperties.put(k, v); localEnvProperties.put(k, v);
} }
}); });
AnyValue propsConf = this.config.getAnyValue("properties"); AnyValue propsConf = this.config.getAnyValue("properties");
if (propsConf == null) { if (propsConf == null) {
final AnyValue resources = config.getAnyValue("resources"); final AnyValue resources = config.getAnyValue("resources");
if (resources != null) { if (resources != null) {
System.err.println("<resources> in application config file is deprecated"); System.err.println("<resources> in application config file is deprecated");
propsConf = resources.getAnyValue("properties"); propsConf = resources.getAnyValue("properties");
} }
} }
if (propsConf != null) { // 设置配置文件中的系统变量 if (propsConf != null) { // 设置配置文件中的系统变量
for (AnyValue prop : propsConf.getAnyValues("property")) { for (AnyValue prop : propsConf.getAnyValues("property")) {
String key = prop.getValue("name", ""); String key = prop.getValue("name", "");
String value = prop.getValue("value"); String value = prop.getValue("value");
if (value != null) { if (value != null) {
localEnvProperties.put(key, value); localEnvProperties.put(key, value);
} }
} }
if (propsConf.getValue("load") != null) { // 加载本地配置项文件 if (propsConf.getValue("load") != null) { // 加载本地配置项文件
for (String dfload : for (String dfload :
propsConf.getValue("load").replace(',', ';').split(";")) { propsConf.getValue("load").replace(',', ';').split(";")) {
if (dfload.trim().isEmpty()) { if (dfload.trim().isEmpty()) {
continue; continue;
} }
final URI df = RedkaleClassLoader.getConfResourceAsURI( final URI df = RedkaleClassLoader.getConfResourceAsURI(
configFromCache ? null : this.confDir.toString(), dfload.trim()); configFromCache ? null : this.confDir.toString(), dfload.trim());
if (df == null) { if (df == null) {
continue; continue;
} }
if (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile()) { if (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile()) {
Properties props = new Properties(); Properties props = new Properties();
try { try {
InputStream in = df.toURL().openStream(); InputStream in = df.toURL().openStream();
props.load(in); props.load(in);
in.close(); in.close();
localEnvProperties.putAll(props); localEnvProperties.putAll(props);
} catch (Exception e) { } catch (Exception e) {
throw new RedkaleException(e); throw new RedkaleException(e);
} }
} }
} }
} }
} }
// 设置Convert默认配置项 // 设置Convert默认配置项
if (System.getProperty("redkale.convert.pool.size") == null if (System.getProperty("redkale.convert.pool.size") == null
&& localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) { && localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) {
localEnvProperties.put("system.property.redkale.convert.pool.size", "128"); localEnvProperties.put("system.property.redkale.convert.pool.size", "128");
} }
if (System.getProperty("redkale.convert.writer.buffer.defsize") == null if (System.getProperty("redkale.convert.writer.buffer.defsize") == null
&& localEnvProperties.getProperty("system.property.redkale.convert.writer.buffer.defsize") == null) { && localEnvProperties.getProperty("system.property.redkale.convert.writer.buffer.defsize") == null) {
localEnvProperties.put("system.property.redkale.convert.writer.buffer.defsize", "4096"); localEnvProperties.put("system.property.redkale.convert.writer.buffer.defsize", "4096");
} }
} }
/** 读取本地DataSource、CacheSource配置 */ /** 读取本地DataSource、CacheSource配置 */
private void initSourceProperties() { private void initSourceProperties() {
if ("file".equals(this.confDir.getScheme())) { if ("file".equals(this.confDir.getScheme())) {
File sourceFile = new File(new File(confDir), "source.properties"); File sourceFile = new File(new File(confDir), "source.properties");
if (sourceFile.isFile() && sourceFile.canRead()) { if (sourceFile.isFile() && sourceFile.canRead()) {
Properties props = new Properties(); Properties props = new Properties();
try { try {
InputStream in = new FileInputStream(sourceFile); InputStream in = new FileInputStream(sourceFile);
props.load(in); props.load(in);
in.close(); in.close();
} catch (IOException e) { } catch (IOException e) {
throw new RedkaleException(e); throw new RedkaleException(e);
} }
this.localEnvProperties.putAll(props); this.localEnvProperties.putAll(props);
} else { } else {
// 兼容 persistence.xml 【已废弃】 // 兼容 persistence.xml 【已废弃】
File persist = new File(new File(confDir), "persistence.xml"); File persist = new File(new File(confDir), "persistence.xml");
if (persist.isFile() && persist.canRead()) { if (persist.isFile() && persist.canRead()) {
System.err.println("persistence.xml is deprecated, replaced by source.properties"); System.err.println("persistence.xml is deprecated, replaced by source.properties");
try { try {
InputStream in = new FileInputStream(persist); InputStream in = new FileInputStream(persist);
this.localEnvProperties.putAll(DataSources.loadSourceProperties(in)); this.localEnvProperties.putAll(DataSources.loadSourceProperties(in));
in.close(); in.close();
} catch (IOException e) { } catch (IOException e) {
throw new RedkaleException(e); throw new RedkaleException(e);
} }
} }
} }
} else { // 从url或jar文件中resources读取 } else { // 从url或jar文件中resources读取
try { try {
final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI( final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(
configFromCache ? null : this.confDir.toString(), "source.properties"); configFromCache ? null : this.confDir.toString(), "source.properties");
InputStream in = sourceURI.toURL().openStream(); InputStream in = sourceURI.toURL().openStream();
Properties props = new Properties(); Properties props = new Properties();
props.load(in); props.load(in);
in.close(); in.close();
this.localEnvProperties.putAll(props); this.localEnvProperties.putAll(props);
} catch (Exception e) { } catch (Exception e) {
// 没有文件 跳过 // 没有文件 跳过
} }
} }
} }
/** 读取本地日志配置 */ /** 读取本地日志配置 */
private void initLogProperties() { private void initLogProperties() {
URI logConfURI; URI logConfURI;
File logConfFile = null; File logConfFile = null;
if (configFromCache) { if (configFromCache) {
logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties"); logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties");
} else if ("file".equals(confDir.getScheme())) { } else if ("file".equals(confDir.getScheme())) {
logConfFile = new File(confDir.getPath(), "logging.properties"); logConfFile = new File(confDir.getPath(), "logging.properties");
logConfURI = logConfFile.toURI(); logConfURI = logConfFile.toURI();
if (!logConfFile.isFile() || !logConfFile.canRead()) { if (!logConfFile.isFile() || !logConfFile.canRead()) {
logConfFile = null; logConfFile = null;
} }
} else { } else {
logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties"); logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties");
} }
if (!"file".equals(confDir.getScheme()) || logConfFile != null) { if (!"file".equals(confDir.getScheme()) || logConfFile != null) {
try { try {
InputStream fin = logConfURI.toURL().openStream(); InputStream fin = logConfURI.toURL().openStream();
Properties properties0 = new Properties(); Properties properties0 = new Properties();
properties0.load(fin); properties0.load(fin);
fin.close(); fin.close();
properties0.forEach(locaLogProperties::put); properties0.forEach(locaLogProperties::put);
} catch (IOException e) { } catch (IOException e) {
throw new RedkaleException("read logging.properties error", e); throw new RedkaleException("read logging.properties error", e);
} }
} }
if (compileMode) { if (compileMode) {
putReflectionClass(java.lang.Class.class.getName()); putReflectionClass(java.lang.Class.class.getName());
putReflectionPublicConstructors(SimpleFormatter.class, SimpleFormatter.class.getName()); putReflectionPublicConstructors(SimpleFormatter.class, SimpleFormatter.class.getName());
putReflectionPublicConstructors(LoggingSearchHandler.class, LoggingSearchHandler.class.getName()); putReflectionPublicConstructors(LoggingSearchHandler.class, LoggingSearchHandler.class.getName());
putReflectionPublicConstructors(LoggingFileHandler.class, LoggingFileHandler.class.getName()); putReflectionPublicConstructors(LoggingFileHandler.class, LoggingFileHandler.class.getName());
putReflectionPublicConstructors( putReflectionPublicConstructors(
LoggingFileHandler.LoggingFormater.class, LoggingFileHandler.LoggingFormater.class.getName()); LoggingFileHandler.LoggingFormater.class, LoggingFileHandler.LoggingFormater.class.getName());
putReflectionPublicConstructors( putReflectionPublicConstructors(
LoggingFileHandler.LoggingConsoleHandler.class, LoggingFileHandler.LoggingConsoleHandler.class,
LoggingFileHandler.LoggingConsoleHandler.class.getName()); LoggingFileHandler.LoggingConsoleHandler.class.getName());
putReflectionPublicConstructors( putReflectionPublicConstructors(
LoggingFileHandler.LoggingSncpFileHandler.class, LoggingFileHandler.LoggingSncpFileHandler.class,
LoggingFileHandler.LoggingSncpFileHandler.class.getName()); LoggingFileHandler.LoggingSncpFileHandler.class.getName());
} }
} }
/** /**
* 从本地application.xml或application.properties文件加载配置信息 * 从本地application.xml或application.properties文件加载配置信息
* *
* @return 配置信息 * @return 配置信息
* @throws IOException * @throws IOException
*/ */
static AnyValue loadAppConfig() throws IOException { static AnyValue loadAppConfig() throws IOException {
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")) final String home = new File(System.getProperty(RESNAME_APP_HOME, ""))
.getCanonicalPath() .getCanonicalPath()
.replace('\\', '/'); .replace('\\', '/');
String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE); String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE);
if (sysConfFile != null) { if (sysConfFile != null) {
String text; String text;
if (sysConfFile.contains("://")) { if (sysConfFile.contains("://")) {
text = Utility.readThenClose(URI.create(sysConfFile).toURL().openStream()); text = Utility.readThenClose(URI.create(sysConfFile).toURL().openStream());
} else { } else {
File f = new File(sysConfFile); File f = new File(sysConfFile);
if (f.isFile() && f.canRead()) { if (f.isFile() && f.canRead()) {
text = Utility.readThenClose(new FileInputStream(f)); text = Utility.readThenClose(new FileInputStream(f));
} else { } else {
throw new IOException("Read application conf file (" + sysConfFile + ") error "); throw new IOException("Read application conf file (" + sysConfFile + ") error ");
} }
} }
return text.trim().startsWith("<") return text.trim().startsWith("<")
? AnyValue.loadFromXml(text, (k, v) -> v.replace("${" + RESNAME_APP_HOME + "}", home)) ? AnyValue.loadFromXml(text, (k, v) -> v.replace("${" + RESNAME_APP_HOME + "}", home))
.getAnyValue("application") .getAnyValue("application")
: AnyValue.loadFromProperties(text).getAnyValue("redkale"); : AnyValue.loadFromProperties(text).getAnyValue("redkale");
} }
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
URI appConfFile; URI appConfFile;
boolean fromCache = false; boolean fromCache = false;
if (confDir.contains("://")) { // jar内部资源 if (confDir.contains("://")) { // jar内部资源
appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml"); appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml");
try { try {
appConfFile.toURL().openStream().close(); appConfFile.toURL().openStream().close();
} catch (IOException e) { // 没有application.xml就尝试读application.properties } catch (IOException e) { // 没有application.xml就尝试读application.properties
appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.properties"); appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.properties");
} }
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { // 绝对路径 } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { // 绝对路径
File f = new File(confDir, "application.xml"); File f = new File(confDir, "application.xml");
if (f.isFile() && f.canRead()) { if (f.isFile() && f.canRead()) {
appConfFile = f.toURI(); appConfFile = f.toURI();
confDir = f.getParentFile().getCanonicalPath(); confDir = f.getParentFile().getCanonicalPath();
} else { } else {
f = new File(confDir, "application.properties"); f = new File(confDir, "application.properties");
if (f.isFile() && f.canRead()) { if (f.isFile() && f.canRead()) {
appConfFile = f.toURI(); appConfFile = f.toURI();
confDir = f.getParentFile().getCanonicalPath(); confDir = f.getParentFile().getCanonicalPath();
} else { } else {
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir
try { try {
appConfFile.toURL().openStream().close(); appConfFile.toURL().openStream().close();
} catch (IOException e) { // 没有application.xml就尝试读application.properties } catch (IOException e) { // 没有application.xml就尝试读application.properties
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties");
} }
confDir = appConfFile confDir = appConfFile
.toString() .toString()
.replace("/application.xml", "") .replace("/application.xml", "")
.replace("/application.properties", ""); .replace("/application.properties", "");
fromCache = true; fromCache = true;
} }
} }
} else { // 相对路径 } else { // 相对路径
File f = new File(new File(home, confDir), "application.xml"); File f = new File(new File(home, confDir), "application.xml");
if (f.isFile() && f.canRead()) { if (f.isFile() && f.canRead()) {
appConfFile = f.toURI(); appConfFile = f.toURI();
confDir = f.getParentFile().getCanonicalPath(); confDir = f.getParentFile().getCanonicalPath();
} else { } else {
f = new File(new File(home, confDir), "application.properties"); f = new File(new File(home, confDir), "application.properties");
if (f.isFile() && f.canRead()) { if (f.isFile() && f.canRead()) {
appConfFile = f.toURI(); appConfFile = f.toURI();
confDir = f.getParentFile().getCanonicalPath(); confDir = f.getParentFile().getCanonicalPath();
} else { } else {
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir
try { try {
appConfFile.toURL().openStream().close(); appConfFile.toURL().openStream().close();
} catch (IOException e) { // 没有application.xml就尝试读application.properties } catch (IOException e) { // 没有application.xml就尝试读application.properties
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties");
} }
confDir = appConfFile confDir = appConfFile
.toString() .toString()
.replace("/application.xml", "") .replace("/application.xml", "")
.replace("/application.properties", ""); .replace("/application.properties", "");
fromCache = true; fromCache = true;
} }
} }
} }
System.setProperty(RESNAME_APP_CONF_DIR, confDir); System.setProperty(RESNAME_APP_CONF_DIR, confDir);
String text = Utility.readThenClose(appConfFile.toURL().openStream()); String text = Utility.readThenClose(appConfFile.toURL().openStream());
AnyValue conf; AnyValue conf;
if (text.trim().startsWith("<")) { if (text.trim().startsWith("<")) {
conf = AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home)) conf = AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home))
.getAnyValue("application"); .getAnyValue("application");
} else { } else {
conf = AnyValue.loadFromProperties(text).getAnyValue("redkale"); conf = AnyValue.loadFromProperties(text).getAnyValue("redkale");
} }
if (fromCache) { if (fromCache) {
((AnyValueWriter) conf).addValue("[config-from-cache]", "true"); ((AnyValueWriter) conf).addValue("[config-from-cache]", "true");
} }
return conf; return conf;
} }
/** /**
* 检查name是否含特殊字符 * 检查name是否含特殊字符
* *
* @param name * @param name
* @return * @return
*/ */
private static String checkName(String name) { private static String checkName(String name) {
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
return name; return name;
} }
for (char ch : name.toCharArray()) { for (char ch : name.toCharArray()) {
if (!((ch >= '0' && ch <= '9') if (!((ch >= '0' && ch <= '9')
|| (ch >= 'a' && ch <= 'z') || (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z') || (ch >= 'A' && ch <= 'Z')
|| ch == '_' || ch == '_'
|| ch == '.' || ch == '.'
|| ch == '-')) { // 不能含特殊字符 || ch == '-')) { // 不能含特殊字符
throw new RedkaleException("name only 0-9 a-z A-Z _ - ."); throw new RedkaleException("name only 0-9 a-z A-Z _ - .");
} }
} }
return name; return name;
} }
/** /**
* 检查node是否含特殊字符 * 检查node是否含特殊字符
* *
* @param name * @param name
* @return * @return
*/ */
private static String checkNodeid(String nodeid) { private static String checkNodeid(String nodeid) {
if (nodeid == null || nodeid.isEmpty()) { if (nodeid == null || nodeid.isEmpty()) {
return nodeid; return nodeid;
} }
for (char ch : nodeid.toCharArray()) { for (char ch : nodeid.toCharArray()) {
if (!((ch >= '0' && ch <= '9') if (!((ch >= '0' && ch <= '9')
|| (ch >= 'a' && ch <= 'z') || (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z') || (ch >= 'A' && ch <= 'Z')
|| ch == '_' || ch == '_'
|| ch == '.' || ch == '.'
|| ch == '-')) { // 不能含特殊字符 || ch == '-')) { // 不能含特殊字符
throw new RedkaleException("nodeid only 0-9 a-z A-Z _ - ."); throw new RedkaleException("nodeid only 0-9 a-z A-Z _ - .");
} }
} }
return nodeid; return nodeid;
} }
private String getCanonicalPath(File file) { private String getCanonicalPath(File file) {
try { try {
return file.getCanonicalPath(); return file.getCanonicalPath();
} catch (IOException e) { } catch (IOException e) {
return file.getAbsolutePath(); return file.getAbsolutePath();
} }
} }
private File getCanonicalFile(File file) { private File getCanonicalFile(File file) {
try { try {
return file.getCanonicalFile(); return file.getCanonicalFile();
} catch (IOException e) { } catch (IOException e) {
return file; return file;
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -17,59 +17,59 @@ import org.redkale.util.AnyValue;
*/ */
public interface ApplicationListener { public interface ApplicationListener {
/** /**
* 初始化方法 * 初始化方法
* *
* @param config 配置参数 * @param config 配置参数
*/ */
default void init(AnyValue config) {} default void init(AnyValue config) {}
/** /**
* Application在运行start前调用 * Application在运行start前调用
* *
* @param application Application * @param application Application
*/ */
default void onPreStart(Application application) {} default void onPreStart(Application application) {}
/** /**
* 服务全部停掉前被调用 * 服务全部停掉前被调用
* *
* @param application Application * @param application Application
*/ */
default void onServersPreStop(Application application) {} default void onServersPreStop(Application application) {}
/** /**
* 服务全部停掉后被调用 * 服务全部停掉后被调用
* *
* @param application Application * @param application Application
*/ */
default void onServersPostStop(Application application) {} default void onServersPostStop(Application application) {}
/** /**
* Application在运行start后调用 * Application在运行start后调用
* *
* @param application Application * @param application Application
*/ */
default void onPostStart(Application application) {} default void onPostStart(Application application) {}
/** /**
* Application在运行Compile前调用 * Application在运行Compile前调用
* *
* @param application Application * @param application Application
*/ */
default void onPreCompile(Application application) {} default void onPreCompile(Application application) {}
/** /**
* Application在运行Compile后调用 * Application在运行Compile后调用
* *
* @param application Application * @param application Application
*/ */
default void onPostCompile(Application application) {} default void onPostCompile(Application application) {}
/** /**
* Application在运行shutdown前调用 * Application在运行shutdown前调用
* *
* @param application Application * @param application Application
*/ */
default void onPreShutdown(Application application) {} default void onPreShutdown(Application application) {}
} }

View File

@@ -13,40 +13,40 @@ import org.redkale.util.Environment;
/** @author zhangjx */ /** @author zhangjx */
public abstract class BootModule { public abstract class BootModule {
protected final Application application; protected final Application application;
protected final ResourceFactory resourceFactory; protected final ResourceFactory resourceFactory;
protected final Environment environment; protected final Environment environment;
protected BootModule(Application application) { protected BootModule(Application application) {
this.application = application; this.application = application;
this.resourceFactory = Objects.requireNonNull(application.resourceFactory); this.resourceFactory = Objects.requireNonNull(application.resourceFactory);
this.environment = Objects.requireNonNull(application.getEnvironment()); this.environment = Objects.requireNonNull(application.getEnvironment());
} }
protected void removeEnvValue(String name) { protected void removeEnvValue(String name) {
application.envProperties.remove(name); application.envProperties.remove(name);
} }
protected void putEnvValue(Object name, Object value) { protected void putEnvValue(Object name, Object value) {
application.envProperties.put(name, value); application.envProperties.put(name, value);
} }
protected List<ModuleEngine> getModuleEngines() { protected List<ModuleEngine> getModuleEngines() {
return application.getModuleEngines(); return application.getModuleEngines();
} }
protected void reconfigLogging(boolean first, Properties allProps) { protected void reconfigLogging(boolean first, Properties allProps) {
application.loggingModule.reconfigLogging(first, allProps); application.loggingModule.reconfigLogging(first, allProps);
} }
protected void onEnvironmentChanged(String namespace, List<ResourceEvent> events) { protected void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
if (namespace != null && namespace.contains("logging")) { if (namespace != null && namespace.contains("logging")) {
// 日志配置单独处理 // 日志配置单独处理
application.loggingModule.onEnvironmentUpdated(events); application.loggingModule.onEnvironmentUpdated(events);
} else { } else {
application.onEnvironmentChanged(namespace, events); application.onEnvironmentChanged(namespace, events);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -16,126 +16,126 @@ import org.redkale.util.Traces;
*/ */
public abstract class LoggingBaseHandler extends Handler { public abstract class LoggingBaseHandler extends Handler {
// public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n"; // public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n";
// 无threadName、TID // 无threadName、TID
public static final String FORMATTER_FORMAT = "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] %4$s %2$s\r\n%5$s%6$s\r\n"; public static final String FORMATTER_FORMAT = "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] %4$s %2$s\r\n%5$s%6$s\r\n";
// 有threadName // 有threadName
public static final String FORMATTER_FORMAT2 = public static final String FORMATTER_FORMAT2 =
"[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] [%7$s] %4$s %2$s\r\n%5$s%6$s\r\n"; "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] [%7$s] %4$s %2$s\r\n%5$s%6$s\r\n";
// 有threadName、TID // 有threadName、TID
public static final String FORMATTER_FORMAT3 = public static final String FORMATTER_FORMAT3 =
"[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] [%7$s] %8$s %4$s %2$s\r\n%5$s%6$s\r\n"; "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] [%7$s] %8$s %4$s %2$s\r\n%5$s%6$s\r\n";
static boolean traceEnable = false; // 防止设置system.property前调用Traces类导致enable提前初始化 static boolean traceEnable = false; // 防止设置system.property前调用Traces类导致enable提前初始化
/** 默认的日志时间格式化类 与SimpleFormatter的区别在于level不使用本地化 */ /** 默认的日志时间格式化类 与SimpleFormatter的区别在于level不使用本地化 */
public static class LoggingFormater extends Formatter { public static class LoggingFormater extends Formatter {
@Override @Override
public String format(LogRecord log) { public String format(LogRecord log) {
if (log.getThrown() == null if (log.getThrown() == null
&& log.getMessage() != null && log.getMessage() != null
&& log.getMessage().startsWith("------")) { && log.getMessage().startsWith("------")) {
return formatMessage(log) + "\r\n"; return formatMessage(log) + "\r\n";
} }
String source; String source;
if (log.getSourceClassName() != null) { if (log.getSourceClassName() != null) {
source = log.getSourceClassName(); source = log.getSourceClassName();
if (log.getSourceMethodName() != null) { if (log.getSourceMethodName() != null) {
source += " " + log.getSourceMethodName(); source += " " + log.getSourceMethodName();
} }
} else { } else {
source = log.getLoggerName(); source = log.getLoggerName();
} }
String message = formatMessage(log); String message = formatMessage(log);
String throwable = ""; String throwable = "";
if (log.getThrown() != null) { if (log.getThrown() != null) {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw) { PrintWriter pw = new PrintWriter(sw) {
@Override @Override
public void println() { public void println() {
super.print("\r\n"); super.print("\r\n");
} }
}; };
pw.println(); pw.println();
log.getThrown().printStackTrace(pw); log.getThrown().printStackTrace(pw);
pw.close(); pw.close();
throwable = sw.toString(); throwable = sw.toString();
} }
Object[] params = log.getParameters(); Object[] params = log.getParameters();
if (params != null) { if (params != null) {
if (params.length == 1) { if (params.length == 1) {
return String.format( return String.format(
FORMATTER_FORMAT2, FORMATTER_FORMAT2,
log.getInstant().toEpochMilli(), log.getInstant().toEpochMilli(),
source, source,
log.getLoggerName(), log.getLoggerName(),
log.getLevel().getName(), log.getLevel().getName(),
message, message,
throwable, throwable,
params[0]); params[0]);
} else if (params.length == 2) { } else if (params.length == 2) {
return String.format( return String.format(
FORMATTER_FORMAT3, FORMATTER_FORMAT3,
log.getInstant().toEpochMilli(), log.getInstant().toEpochMilli(),
source, source,
log.getLoggerName(), log.getLoggerName(),
log.getLevel().getName(), log.getLevel().getName(),
message, message,
throwable, throwable,
params[0], params[0],
params[1]); params[1]);
} }
} }
return String.format( return String.format(
FORMATTER_FORMAT, FORMATTER_FORMAT,
log.getInstant().toEpochMilli(), log.getInstant().toEpochMilli(),
source, source,
log.getLoggerName(), log.getLoggerName(),
log.getLevel().getName(), log.getLevel().getName(),
message, message,
throwable); throwable);
} }
} }
protected static void fillLogRecord(LogRecord log) { protected static void fillLogRecord(LogRecord log) {
String traceid = null; String traceid = null;
if (traceEnable && Traces.enable()) { if (traceEnable && Traces.enable()) {
traceid = Traces.currentTraceid(); traceid = Traces.currentTraceid();
if (traceid == null || traceid.isEmpty()) { if (traceid == null || traceid.isEmpty()) {
traceid = "[TID:N/A] "; traceid = "[TID:N/A] ";
} else { } else {
traceid = "[TID:" + traceid + "] "; traceid = "[TID:" + traceid + "] ";
} }
} }
if (traceid == null) { if (traceid == null) {
log.setParameters(new String[] {Thread.currentThread().getName()}); log.setParameters(new String[] {Thread.currentThread().getName()});
} else { } else {
log.setParameters(new String[] {Thread.currentThread().getName(), traceid}); log.setParameters(new String[] {Thread.currentThread().getName(), traceid});
} }
} }
public static void initDebugLogConfig() { public static void initDebugLogConfig() {
try { try {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(out); final PrintStream ps = new PrintStream(out);
final String handlerName = final String handlerName =
LoggingFileHandler.LoggingConsoleHandler.class.getName(); // java.util.logging.ConsoleHandler LoggingFileHandler.LoggingConsoleHandler.class.getName(); // java.util.logging.ConsoleHandler
ps.println("handlers = " + handlerName); ps.println("handlers = " + handlerName);
ps.println(".level = FINEST"); ps.println(".level = FINEST");
ps.println("jdk.level = INFO"); ps.println("jdk.level = INFO");
ps.println("sun.level = INFO"); ps.println("sun.level = INFO");
ps.println("javax.level = INFO"); ps.println("javax.level = INFO");
ps.println("com.sun.level = INFO"); ps.println("com.sun.level = INFO");
ps.println("io.level = INFO"); ps.println("io.level = INFO");
ps.println("org.junit.level = INFO"); ps.println("org.junit.level = INFO");
ps.println(handlerName + ".level = FINEST"); ps.println(handlerName + ".level = FINEST");
ps.println(handlerName + ".formatter = " + LoggingFormater.class.getName()); ps.println(handlerName + ".formatter = " + LoggingFormater.class.getName());
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray())); LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
} }
} }

View File

@@ -26,378 +26,378 @@ import org.redkale.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class LoggingFileHandler extends LoggingBaseHandler { public class LoggingFileHandler extends LoggingBaseHandler {
/** SNCP的日志输出Handler */ /** SNCP的日志输出Handler */
public static class LoggingSncpFileHandler extends LoggingFileHandler { public static class LoggingSncpFileHandler extends LoggingFileHandler {
@Override @Override
public String getPrefix() { public String getPrefix() {
return "sncp-"; return "sncp-";
} }
} }
public static class LoggingConsoleHandler extends ConsoleHandler { public static class LoggingConsoleHandler extends ConsoleHandler {
private Pattern denyRegx; private Pattern denyRegx;
public LoggingConsoleHandler() { public LoggingConsoleHandler() {
super(); super();
setFormatter(new LoggingFormater()); setFormatter(new LoggingFormater());
configure(); configure();
} }
private void configure() { private void configure() {
LogManager manager = LogManager.getLogManager(); LogManager manager = LogManager.getLogManager();
String denyregxstr = manager.getProperty(LoggingConsoleHandler.class.getName() + ".denyregx"); String denyregxstr = manager.getProperty(LoggingConsoleHandler.class.getName() + ".denyregx");
if (denyregxstr == null) { if (denyregxstr == null) {
denyregxstr = manager.getProperty("java.util.logging.ConsoleHandler.denyregx"); denyregxstr = manager.getProperty("java.util.logging.ConsoleHandler.denyregx");
} }
try { try {
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) { if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
this.denyRegx = Pattern.compile(denyregxstr); this.denyRegx = Pattern.compile(denyregxstr);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
} }
@Override @Override
public void publish(LogRecord log) { public void publish(LogRecord log) {
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) { if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
return; return;
} }
fillLogRecord(log); fillLogRecord(log);
super.publish(log); super.publish(log);
} }
} }
protected final LinkedBlockingQueue<LogRecord> logQueue = new LinkedBlockingQueue(); protected final LinkedBlockingQueue<LogRecord> logQueue = new LinkedBlockingQueue();
protected String pattern; protected String pattern;
protected String patternDateFormat; // 需要时间格式化 protected String patternDateFormat; // 需要时间格式化
protected String unusual; // 不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中 protected String unusual; // 不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中
protected String unusualDateFormat; // 需要时间格式化 protected String unusualDateFormat; // 需要时间格式化
private int limit; // 文件大小限制 private int limit; // 文件大小限制
private final AtomicInteger logIndex = new AtomicInteger(); private final AtomicInteger logIndex = new AtomicInteger();
private final AtomicInteger logUnusualIndex = new AtomicInteger(); private final AtomicInteger logUnusualIndex = new AtomicInteger();
private int count = 1; // 文件限制 private int count = 1; // 文件限制
private long tomorrow; private long tomorrow;
protected boolean append; protected boolean append;
protected Pattern denyRegx; protected Pattern denyRegx;
private final AtomicLong logLength = new AtomicLong(); private final AtomicLong logLength = new AtomicLong();
private final AtomicLong logUnusualLength = new AtomicLong(); private final AtomicLong logUnusualLength = new AtomicLong();
private File logFile; private File logFile;
private File logUnusualFile; private File logUnusualFile;
private OutputStream logStream; private OutputStream logStream;
private OutputStream logUnusualStream; private OutputStream logUnusualStream;
public LoggingFileHandler() { public LoggingFileHandler() {
updateTomorrow(); updateTomorrow();
configure(); configure();
open(); open();
} }
private void updateTomorrow() { private void updateTomorrow() {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0); cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0); cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0); cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.DAY_OF_YEAR, 1); cal.add(Calendar.DAY_OF_YEAR, 1);
long t = cal.getTimeInMillis(); long t = cal.getTimeInMillis();
if (this.tomorrow != t) { if (this.tomorrow != t) {
logIndex.set(0); logIndex.set(0);
} }
this.tomorrow = t; this.tomorrow = t;
} }
private void open() { private void open() {
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread"; final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
new Thread() { new Thread() {
{ {
setName(name); setName(name);
setDaemon(true); setDaemon(true);
} }
@Override @Override
public void run() { public void run() {
while (true) { while (true) {
try { try {
LogRecord log = logQueue.take(); LogRecord log = logQueue.take();
final boolean bigger = (limit > 0 && limit <= logLength.get()); final boolean bigger = (limit > 0 && limit <= logLength.get());
final boolean changeday = tomorrow <= log.getMillis(); final boolean changeday = tomorrow <= log.getMillis();
if (bigger || changeday) { if (bigger || changeday) {
updateTomorrow(); updateTomorrow();
if (logStream != null) { if (logStream != null) {
logStream.close(); logStream.close();
if (bigger) { if (bigger) {
for (int i = Math.min(count - 2, logIndex.get() - 1); i > 0; i--) { for (int i = Math.min(count - 2, logIndex.get() - 1); i > 0; i--) {
File greater = new File(logFile.getPath() + "." + i); File greater = new File(logFile.getPath() + "." + i);
if (greater.exists()) { if (greater.exists()) {
Files.move( Files.move(
greater.toPath(), greater.toPath(),
new File(logFile.getPath() + "." + (i + 1)).toPath(), new File(logFile.getPath() + "." + (i + 1)).toPath(),
REPLACE_EXISTING, REPLACE_EXISTING,
ATOMIC_MOVE); ATOMIC_MOVE);
} }
} }
Files.move( Files.move(
logFile.toPath(), logFile.toPath(),
new File(logFile.getPath() + ".1").toPath(), new File(logFile.getPath() + ".1").toPath(),
REPLACE_EXISTING, REPLACE_EXISTING,
ATOMIC_MOVE); ATOMIC_MOVE);
} else { } else {
if (logFile.exists() && logFile.length() < 1) { if (logFile.exists() && logFile.length() < 1) {
Files.delete(logFile.toPath()); Files.delete(logFile.toPath());
} }
} }
logStream = null; logStream = null;
} }
} }
if (unusual != null && changeday && logUnusualStream != null) { if (unusual != null && changeday && logUnusualStream != null) {
logUnusualStream.close(); logUnusualStream.close();
if (limit > 0 && limit <= logUnusualLength.get()) { if (limit > 0 && limit <= logUnusualLength.get()) {
for (int i = Math.min(count - 2, logUnusualIndex.get() - 1); i > 0; i--) { for (int i = Math.min(count - 2, logUnusualIndex.get() - 1); i > 0; i--) {
File greater = new File(logUnusualFile.getPath() + "." + i); File greater = new File(logUnusualFile.getPath() + "." + i);
if (greater.exists()) { if (greater.exists()) {
Files.move( Files.move(
greater.toPath(), greater.toPath(),
new File(logUnusualFile.getPath() + "." + (i + 1)).toPath(), new File(logUnusualFile.getPath() + "." + (i + 1)).toPath(),
REPLACE_EXISTING, REPLACE_EXISTING,
ATOMIC_MOVE); ATOMIC_MOVE);
} }
} }
Files.move( Files.move(
logUnusualFile.toPath(), logUnusualFile.toPath(),
new File(logUnusualFile.getPath() + ".1").toPath(), new File(logUnusualFile.getPath() + ".1").toPath(),
REPLACE_EXISTING, REPLACE_EXISTING,
ATOMIC_MOVE); ATOMIC_MOVE);
} else { } else {
if (logUnusualFile.exists() && logUnusualFile.length() < 1) { if (logUnusualFile.exists() && logUnusualFile.length() < 1) {
Files.delete(logUnusualFile.toPath()); Files.delete(logUnusualFile.toPath());
} }
} }
logUnusualStream = null; logUnusualStream = null;
} }
if (logStream == null) { if (logStream == null) {
logIndex.incrementAndGet(); logIndex.incrementAndGet();
logFile = new File( logFile = new File(
patternDateFormat == null patternDateFormat == null
? pattern ? pattern
: Times.formatTime(patternDateFormat, -1, System.currentTimeMillis())); : Times.formatTime(patternDateFormat, -1, System.currentTimeMillis()));
logFile.getParentFile().mkdirs(); logFile.getParentFile().mkdirs();
logLength.set(logFile.length()); logLength.set(logFile.length());
logStream = new FileOutputStream(logFile, append); logStream = new FileOutputStream(logFile, append);
} }
if (unusual != null && logUnusualStream == null) { if (unusual != null && logUnusualStream == null) {
logUnusualIndex.incrementAndGet(); logUnusualIndex.incrementAndGet();
logUnusualFile = new File( logUnusualFile = new File(
unusualDateFormat == null unusualDateFormat == null
? unusual ? unusual
: Times.formatTime(unusualDateFormat, -1, System.currentTimeMillis())); : Times.formatTime(unusualDateFormat, -1, System.currentTimeMillis()));
logUnusualFile.getParentFile().mkdirs(); logUnusualFile.getParentFile().mkdirs();
logUnusualLength.set(logUnusualFile.length()); logUnusualLength.set(logUnusualFile.length());
logUnusualStream = new FileOutputStream(logUnusualFile, append); logUnusualStream = new FileOutputStream(logUnusualFile, append);
} }
// ----------------------写日志------------------------- // ----------------------写日志-------------------------
String message = getFormatter().format(log); String message = getFormatter().format(log);
String encoding = getEncoding(); String encoding = getEncoding();
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding); byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
logStream.write(bytes); logStream.write(bytes);
logLength.addAndGet(bytes.length); logLength.addAndGet(bytes.length);
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) { if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
logUnusualStream.write(bytes); logUnusualStream.write(bytes);
logUnusualLength.addAndGet(bytes.length); logUnusualLength.addAndGet(bytes.length);
} }
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) { if (err != null) {
err.error(null, e, ErrorManager.WRITE_FAILURE); err.error(null, e, ErrorManager.WRITE_FAILURE);
} }
} }
} }
} }
}.start(); }.start();
} }
public String getPrefix() { public String getPrefix() {
return ""; return "";
} }
private void configure() { private void configure() {
LogManager manager = LogManager.getLogManager(); LogManager manager = LogManager.getLogManager();
String cname = LoggingFileHandler.class.getName(); String cname = LoggingFileHandler.class.getName();
this.pattern = manager.getProperty(cname + ".pattern"); this.pattern = manager.getProperty(cname + ".pattern");
if (this.pattern == null) { if (this.pattern == null) {
this.pattern = "logs-%tm/" + getPrefix() + "log-%td.log"; this.pattern = "logs-%tm/" + getPrefix() + "log-%td.log";
} else { } else {
int pos = this.pattern.lastIndexOf('/'); int pos = this.pattern.lastIndexOf('/');
if (pos > 0) { if (pos > 0) {
this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1); this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1);
} else { } else {
this.pattern = getPrefix() + this.pattern; this.pattern = getPrefix() + this.pattern;
} }
} }
if (this.pattern != null && this.pattern.contains("%")) { // 需要时间格式化 if (this.pattern != null && this.pattern.contains("%")) { // 需要时间格式化
this.patternDateFormat = this.pattern; this.patternDateFormat = this.pattern;
Times.formatTime(this.patternDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确 Times.formatTime(this.patternDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
} }
String unusualstr = manager.getProperty(cname + ".unusual"); String unusualstr = manager.getProperty(cname + ".unusual");
if (unusualstr != null) { if (unusualstr != null) {
int pos = unusualstr.lastIndexOf('/'); int pos = unusualstr.lastIndexOf('/');
if (pos > 0) { if (pos > 0) {
this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1); this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1);
} else { } else {
this.unusual = getPrefix() + unusualstr; this.unusual = getPrefix() + unusualstr;
} }
} }
if (this.unusual != null && this.unusual.contains("%")) { // 需要时间格式化 if (this.unusual != null && this.unusual.contains("%")) { // 需要时间格式化
this.unusualDateFormat = this.unusual; this.unusualDateFormat = this.unusual;
Times.formatTime(this.unusualDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确 Times.formatTime(this.unusualDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
} }
String limitstr = manager.getProperty(cname + ".limit"); String limitstr = manager.getProperty(cname + ".limit");
try { try {
if (limitstr != null) { if (limitstr != null) {
limitstr = limitstr.toUpperCase(); limitstr = limitstr.toUpperCase();
boolean g = limitstr.indexOf('G') > 0; boolean g = limitstr.indexOf('G') > 0;
boolean m = limitstr.indexOf('M') > 0; boolean m = limitstr.indexOf('M') > 0;
boolean k = limitstr.indexOf('K') > 0; boolean k = limitstr.indexOf('K') > 0;
int ls = Math.abs(Integer.decode(limitstr.replace("G", "") int ls = Math.abs(Integer.decode(limitstr.replace("G", "")
.replace("M", "") .replace("M", "")
.replace("K", "") .replace("K", "")
.replace("B", ""))); .replace("B", "")));
if (g) { if (g) {
ls *= 1024 * 1024 * 1024; ls *= 1024 * 1024 * 1024;
} else if (m) { } else if (m) {
ls *= 1024 * 1024; ls *= 1024 * 1024;
} else if (k) { } else if (k) {
ls *= 1024; ls *= 1024;
} }
this.limit = ls; this.limit = ls;
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String countstr = manager.getProperty(cname + ".count"); String countstr = manager.getProperty(cname + ".count");
try { try {
if (countstr != null) { if (countstr != null) {
this.count = Math.max(1, Math.abs(Integer.decode(countstr))); this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String appendstr = manager.getProperty(cname + ".append"); String appendstr = manager.getProperty(cname + ".append");
try { try {
if (appendstr != null) { if (appendstr != null) {
this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr); this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String levelstr = manager.getProperty(cname + ".level"); String levelstr = manager.getProperty(cname + ".level");
try { try {
if (levelstr != null) { if (levelstr != null) {
Level l = Level.parse(levelstr); Level l = Level.parse(levelstr);
setLevel(l != null ? l : Level.ALL); setLevel(l != null ? l : Level.ALL);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String filterstr = manager.getProperty(cname + ".filter"); String filterstr = manager.getProperty(cname + ".filter");
try { try {
if (filterstr != null) { if (filterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr); Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFilter((Filter) clz.getDeclaredConstructor().newInstance()); setFilter((Filter) clz.getDeclaredConstructor().newInstance());
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String formatterstr = manager.getProperty(cname + ".formatter"); String formatterstr = manager.getProperty(cname + ".formatter");
try { try {
if (formatterstr != null) { if (formatterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr); Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance()); setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
if (getFormatter() == null) { if (getFormatter() == null) {
setFormatter(new SimpleFormatter()); setFormatter(new SimpleFormatter());
} }
String encodingstr = manager.getProperty(cname + ".encoding"); String encodingstr = manager.getProperty(cname + ".encoding");
try { try {
if (encodingstr != null) { if (encodingstr != null) {
setEncoding(encodingstr); setEncoding(encodingstr);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String denyregxstr = manager.getProperty(cname + ".denyregx"); String denyregxstr = manager.getProperty(cname + ".denyregx");
try { try {
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) { if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
denyRegx = Pattern.compile(denyregxstr); denyRegx = Pattern.compile(denyregxstr);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
} }
@Override @Override
public void publish(LogRecord log) { public void publish(LogRecord log) {
if (!isLoggable(log)) { if (!isLoggable(log)) {
return; return;
} }
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) { if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
return; return;
} }
fillLogRecord(log); fillLogRecord(log);
logQueue.offer(log); logQueue.offer(log);
} }
@Override @Override
public void flush() { public void flush() {
try { try {
if (logStream != null) { if (logStream != null) {
logStream.flush(); logStream.flush();
} }
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) { if (err != null) {
err.error(null, e, ErrorManager.FLUSH_FAILURE); err.error(null, e, ErrorManager.FLUSH_FAILURE);
} }
} }
} }
@Override @Override
public void close() throws SecurityException { public void close() throws SecurityException {
try { try {
if (logStream != null) { if (logStream != null) {
logStream.close(); logStream.close();
} }
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) { if (err != null) {
err.error(null, e, ErrorManager.CLOSE_FAILURE); err.error(null, e, ErrorManager.CLOSE_FAILURE);
} }
} }
} }
} }

View File

@@ -31,162 +31,162 @@ import org.redkale.util.Environment;
*/ */
class LoggingModule extends BootModule { class LoggingModule extends BootModule {
// 日志配置资源 // 日志配置资源
private final Properties loggingProperties = new Properties(); private final Properties loggingProperties = new Properties();
LoggingModule(Application application) { LoggingModule(Application application) {
super(application); super(application);
} }
/** /**
* 配置变更 * 配置变更
* *
* @param events 变更项 * @param events 变更项
*/ */
public void onEnvironmentUpdated(List<ResourceEvent> events) { public void onEnvironmentUpdated(List<ResourceEvent> events) {
Set<String> loggingRemovedKeys = new HashSet<>(); Set<String> loggingRemovedKeys = new HashSet<>();
Properties loggingChangedProps = new Properties(); Properties loggingChangedProps = new Properties();
for (ResourceEvent event : events) { for (ResourceEvent event : events) {
if (event.newValue() == null) { if (event.newValue() == null) {
if (loggingProperties.containsKey(event.name())) { if (loggingProperties.containsKey(event.name())) {
loggingRemovedKeys.add(event.name()); loggingRemovedKeys.add(event.name());
} }
} else { } else {
loggingChangedProps.put(event.name(), event.newValue()); loggingChangedProps.put(event.name(), event.newValue());
} }
} }
if (!loggingRemovedKeys.isEmpty() || !loggingChangedProps.isEmpty()) { if (!loggingRemovedKeys.isEmpty() || !loggingChangedProps.isEmpty()) {
Properties newProps = new Properties(this.loggingProperties); Properties newProps = new Properties(this.loggingProperties);
loggingRemovedKeys.forEach(newProps::remove); loggingRemovedKeys.forEach(newProps::remove);
newProps.putAll(loggingChangedProps); newProps.putAll(loggingChangedProps);
reconfigLogging(false, newProps); reconfigLogging(false, newProps);
} }
} }
/** /**
* 设置日志策略 * 设置日志策略
* *
* @param first 是否首次设置 * @param first 是否首次设置
* @param allProps 配置项全量 * @param allProps 配置项全量
*/ */
public void reconfigLogging(boolean first, Properties allProps) { public void reconfigLogging(boolean first, Properties allProps) {
String searchRawHandler = "java.util.logging.SearchHandler"; String searchRawHandler = "java.util.logging.SearchHandler";
String searchReadHandler = LoggingSearchHandler.class.getName(); String searchReadHandler = LoggingSearchHandler.class.getName();
Properties onlyLogProps = new Properties(); Properties onlyLogProps = new Properties();
Environment envs = this.environment; Environment envs = this.environment;
allProps.entrySet().forEach(x -> { allProps.entrySet().forEach(x -> {
String key = x.getKey().toString(); String key = x.getKey().toString();
if (key.startsWith("java.util.logging.") || key.contains(".level") || key.equals("handlers")) { if (key.startsWith("java.util.logging.") || key.contains(".level") || key.equals("handlers")) {
String val = envs.getPropertyValue(x.getValue() String val = envs.getPropertyValue(x.getValue()
.toString() .toString()
.replace("%m", "%tY%tm") .replace("%m", "%tY%tm")
.replace("%d", "%tY%tm%td") // 兼容旧时间格式 .replace("%d", "%tY%tm%td") // 兼容旧时间格式
.replace(searchRawHandler, searchReadHandler)); .replace(searchRawHandler, searchReadHandler));
onlyLogProps.put(key.replace(searchRawHandler, searchReadHandler), val); onlyLogProps.put(key.replace(searchRawHandler, searchReadHandler), val);
} }
}); });
if (onlyLogProps.getProperty("java.util.logging.FileHandler.formatter") == null) { if (onlyLogProps.getProperty("java.util.logging.FileHandler.formatter") == null) {
if (application.isCompileMode()) { if (application.isCompileMode()) {
onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName()); onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName());
if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) { if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
onlyLogProps.setProperty( onlyLogProps.setProperty(
"java.util.logging.SimpleFormatter.format", "java.util.logging.SimpleFormatter.format",
LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n")); LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
} }
} else { } else {
onlyLogProps.setProperty( onlyLogProps.setProperty(
"java.util.logging.FileHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName()); "java.util.logging.FileHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName());
} }
} }
if (onlyLogProps.getProperty("java.util.logging.ConsoleHandler.formatter") == null) { if (onlyLogProps.getProperty("java.util.logging.ConsoleHandler.formatter") == null) {
if (application.isCompileMode()) { if (application.isCompileMode()) {
onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", SimpleFormatter.class.getName()); onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", SimpleFormatter.class.getName());
if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) { if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
onlyLogProps.setProperty( onlyLogProps.setProperty(
"java.util.logging.SimpleFormatter.format", "java.util.logging.SimpleFormatter.format",
LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n")); LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
} }
} else { } else {
onlyLogProps.setProperty( onlyLogProps.setProperty(
"java.util.logging.ConsoleHandler.formatter", "java.util.logging.ConsoleHandler.formatter",
LoggingFileHandler.LoggingFormater.class.getName()); LoggingFileHandler.LoggingFormater.class.getName());
} }
} }
if (!application.isCompileMode()) { // ConsoleHandler替换成LoggingConsoleHandler if (!application.isCompileMode()) { // ConsoleHandler替换成LoggingConsoleHandler
final String handlers = onlyLogProps.getProperty("handlers"); final String handlers = onlyLogProps.getProperty("handlers");
if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) { if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) {
final String consoleHandlerClass = LoggingFileHandler.LoggingConsoleHandler.class.getName(); final String consoleHandlerClass = LoggingFileHandler.LoggingConsoleHandler.class.getName();
onlyLogProps.setProperty( onlyLogProps.setProperty(
"handlers", handlers.replace("java.util.logging.ConsoleHandler", consoleHandlerClass)); "handlers", handlers.replace("java.util.logging.ConsoleHandler", consoleHandlerClass));
Properties prop = new Properties(); Properties prop = new Properties();
String prefix = consoleHandlerClass + "."; String prefix = consoleHandlerClass + ".";
onlyLogProps.entrySet().forEach(x -> { onlyLogProps.entrySet().forEach(x -> {
if (x.getKey().toString().startsWith("java.util.logging.ConsoleHandler.")) { if (x.getKey().toString().startsWith("java.util.logging.ConsoleHandler.")) {
prop.put( prop.put(
x.getKey().toString().replace("java.util.logging.ConsoleHandler.", prefix), x.getKey().toString().replace("java.util.logging.ConsoleHandler.", prefix),
x.getValue()); x.getValue());
} }
}); });
prop.entrySet().forEach(x -> { prop.entrySet().forEach(x -> {
onlyLogProps.put(x.getKey(), x.getValue()); onlyLogProps.put(x.getKey(), x.getValue());
}); });
} }
} }
String fileHandlerPattern = onlyLogProps.getProperty("java.util.logging.FileHandler.pattern"); String fileHandlerPattern = onlyLogProps.getProperty("java.util.logging.FileHandler.pattern");
if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { // 带日期格式 if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { // 带日期格式
final String fileHandlerClass = LoggingFileHandler.class.getName(); final String fileHandlerClass = LoggingFileHandler.class.getName();
Properties prop = new Properties(); Properties prop = new Properties();
final String handlers = onlyLogProps.getProperty("handlers"); final String handlers = onlyLogProps.getProperty("handlers");
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) { if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
// singletonrun模式下不输出文件日志 // singletonrun模式下不输出文件日志
prop.setProperty( prop.setProperty(
"handlers", "handlers",
handlers.replace( handlers.replace(
"java.util.logging.FileHandler", "java.util.logging.FileHandler",
application.isSingletonMode() || application.isCompileMode() ? "" : fileHandlerClass)); application.isSingletonMode() || application.isCompileMode() ? "" : fileHandlerClass));
} }
if (!prop.isEmpty()) { if (!prop.isEmpty()) {
String prefix = fileHandlerClass + "."; String prefix = fileHandlerClass + ".";
onlyLogProps.entrySet().forEach(x -> { onlyLogProps.entrySet().forEach(x -> {
if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) { if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) {
prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue()); prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue());
} }
}); });
prop.entrySet().forEach(x -> onlyLogProps.put(x.getKey(), x.getValue())); prop.entrySet().forEach(x -> onlyLogProps.put(x.getKey(), x.getValue()));
} }
if (!application.isCompileMode()) { if (!application.isCompileMode()) {
onlyLogProps.put( onlyLogProps.put(
SncpClient.class.getSimpleName() + ".handlers", SncpClient.class.getSimpleName() + ".handlers",
LoggingFileHandler.LoggingSncpFileHandler.class.getName()); LoggingFileHandler.LoggingSncpFileHandler.class.getName());
} }
} }
if (application.isCompileMode()) { if (application.isCompileMode()) {
onlyLogProps.put("handlers", "java.util.logging.ConsoleHandler"); onlyLogProps.put("handlers", "java.util.logging.ConsoleHandler");
Map newprop = new HashMap(onlyLogProps); Map newprop = new HashMap(onlyLogProps);
newprop.forEach((k, v) -> { newprop.forEach((k, v) -> {
if (k.toString().startsWith("java.util.logging.FileHandler.")) { if (k.toString().startsWith("java.util.logging.FileHandler.")) {
onlyLogProps.remove(k); onlyLogProps.remove(k);
} }
}); });
} }
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(out); final PrintStream ps = new PrintStream(out);
onlyLogProps.forEach((x, y) -> ps.println(x + "=" + y)); onlyLogProps.forEach((x, y) -> ps.println(x + "=" + y));
try { try {
LogManager manager = LogManager.getLogManager(); LogManager manager = LogManager.getLogManager();
manager.readConfiguration(new ByteArrayInputStream(out.toByteArray())); manager.readConfiguration(new ByteArrayInputStream(out.toByteArray()));
this.loggingProperties.clear(); this.loggingProperties.clear();
this.loggingProperties.putAll(onlyLogProps); this.loggingProperties.putAll(onlyLogProps);
Enumeration<String> en = manager.getLoggerNames(); Enumeration<String> en = manager.getLoggerNames();
while (en.hasMoreElements()) { while (en.hasMoreElements()) {
for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) { for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) {
if (handler instanceof LoggingSearchHandler) { if (handler instanceof LoggingSearchHandler) {
((LoggingSearchHandler) handler).application = application; ((LoggingSearchHandler) handler).application = application;
} }
} }
} }
} catch (IOException e) { // 不会发生 } catch (IOException e) { // 不会发生
} }
} }
} }

View File

@@ -29,325 +29,325 @@ import org.redkale.util.*;
*/ */
public class LoggingSearchHandler extends LoggingBaseHandler { public class LoggingSearchHandler extends LoggingBaseHandler {
protected static final String DEFAULT_TABLE_NAME = "log-record"; protected static final String DEFAULT_TABLE_NAME = "log-record";
protected final LinkedBlockingQueue<SearchLogRecord> logqueue = new LinkedBlockingQueue(); protected final LinkedBlockingQueue<SearchLogRecord> logqueue = new LinkedBlockingQueue();
protected final AtomicInteger retryCount = new AtomicInteger(3); protected final AtomicInteger retryCount = new AtomicInteger(3);
protected String tag = DEFAULT_TABLE_NAME; // 用于表前缀, 默认是 protected String tag = DEFAULT_TABLE_NAME; // 用于表前缀, 默认是
protected String tagDateFormat; // 需要时间格式化 protected String tagDateFormat; // 需要时间格式化
protected String pattern; protected String pattern;
protected Pattern denyRegx; protected Pattern denyRegx;
protected String sourceResourceName; protected String sourceResourceName;
protected SearchSource source; protected SearchSource source;
// 在LogManager.getLogManager().readConfiguration执行完后通过反射注入Application // 在LogManager.getLogManager().readConfiguration执行完后通过反射注入Application
protected Application application; protected Application application;
public LoggingSearchHandler() { public LoggingSearchHandler() {
configure(); configure();
open(); open();
} }
private void open() { private void open() {
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread"; final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
final int batchSize = 100; // 批量最多100条 final int batchSize = 100; // 批量最多100条
final List<SearchLogRecord> logList = new ArrayList<>(); final List<SearchLogRecord> logList = new ArrayList<>();
final Formatter formatter = new LoggingBaseHandler.LoggingFormater(); final Formatter formatter = new LoggingBaseHandler.LoggingFormater();
final PrintStream outStream = System.out; final PrintStream outStream = System.out;
new Thread() { new Thread() {
{ {
setName(name); setName(name);
setDaemon(true); setDaemon(true);
} }
@Override @Override
public void run() { public void run() {
while (true) { while (true) {
try { try {
SearchLogRecord log = logqueue.take(); SearchLogRecord log = logqueue.take();
while (source == null && retryCount.get() > 0) initSource(); while (source == null && retryCount.get() > 0) initSource();
// ----------------------写日志------------------------- // ----------------------写日志-------------------------
if (source == null) { // source加载失败 if (source == null) { // source加载失败
outStream.print(formatter.format(log.rawLog)); outStream.print(formatter.format(log.rawLog));
} else { } else {
logList.add(log); logList.add(log);
int size = batchSize; int size = batchSize;
while (--size > 0) { while (--size > 0) {
log = logqueue.poll(); log = logqueue.poll();
if (log == null) { if (log == null) {
break; break;
} }
logList.add(log); logList.add(log);
} }
source.insert(logList); source.insert(logList);
} }
} catch (Exception e) { } catch (Exception e) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) { if (err != null) {
err.error(null, e, ErrorManager.WRITE_FAILURE); err.error(null, e, ErrorManager.WRITE_FAILURE);
} }
} finally { } finally {
logList.clear(); logList.clear();
} }
} }
} }
}.start(); }.start();
} }
private void initSource() { private void initSource() {
if (retryCount.get() < 1) { if (retryCount.get() < 1) {
return; return;
} }
try { try {
Utility.sleep(3000); // 如果SearchSource自身在打印日志需要停顿一点时间让SearchSource初始化完成 Utility.sleep(3000); // 如果SearchSource自身在打印日志需要停顿一点时间让SearchSource初始化完成
if (application == null) { if (application == null) {
Utility.sleep(3000); Utility.sleep(3000);
} }
if (application == null) { if (application == null) {
return; return;
} }
this.source = application.getResourceFactory().find(sourceResourceName, SearchSource.class); this.source = application.getResourceFactory().find(sourceResourceName, SearchSource.class);
if (retryCount.get() == 1 && this.source == null) { if (retryCount.get() == 1 && this.source == null) {
System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")"); System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")");
} }
} catch (Exception t) { } catch (Exception t) {
ErrorManager err = getErrorManager(); ErrorManager err = getErrorManager();
if (err != null) { if (err != null) {
err.error(null, t, ErrorManager.WRITE_FAILURE); err.error(null, t, ErrorManager.WRITE_FAILURE);
} }
} finally { } finally {
retryCount.decrementAndGet(); retryCount.decrementAndGet();
} }
} }
private static boolean checkTagName(String name) { // 只能是字母、数字、短横、点、%、$和下划线 private static boolean checkTagName(String name) { // 只能是字母、数字、短横、点、%、$和下划线
if (name.isEmpty()) { if (name.isEmpty()) {
return false; return false;
} }
for (char ch : name.toCharArray()) { for (char ch : name.toCharArray()) {
if (ch >= '0' && ch <= '9') { if (ch >= '0' && ch <= '9') {
continue; continue;
} }
if (ch >= 'a' && ch <= 'z') { if (ch >= 'a' && ch <= 'z') {
continue; continue;
} }
if (ch >= 'A' && ch <= 'Z') { if (ch >= 'A' && ch <= 'Z') {
continue; continue;
} }
if (ch == '_' || ch == '-' || ch == '%' || ch == '$' || ch == '.') { if (ch == '_' || ch == '-' || ch == '%' || ch == '$' || ch == '.') {
continue; continue;
} }
return false; return false;
} }
return true; return true;
} }
private void configure() { private void configure() {
LogManager manager = LogManager.getLogManager(); LogManager manager = LogManager.getLogManager();
String cname = getClass().getName(); String cname = getClass().getName();
this.sourceResourceName = manager.getProperty(cname + ".source"); this.sourceResourceName = manager.getProperty(cname + ".source");
if (this.sourceResourceName == null || this.sourceResourceName.isEmpty()) { if (this.sourceResourceName == null || this.sourceResourceName.isEmpty()) {
throw new RedkaleException("not found logging.property " + cname + ".source"); throw new RedkaleException("not found logging.property " + cname + ".source");
} }
String tagStr = manager.getProperty(cname + ".tag"); String tagStr = manager.getProperty(cname + ".tag");
if (tagStr != null && !tagStr.isEmpty()) { if (tagStr != null && !tagStr.isEmpty()) {
if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) { if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) {
throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagStr); throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagStr);
} }
this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty(SYSNAME_APP_NAME, "")); this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty(SYSNAME_APP_NAME, ""));
if (this.tag.contains("%")) { if (this.tag.contains("%")) {
this.tagDateFormat = this.tag; this.tagDateFormat = this.tag;
Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确 Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
} }
} }
String levelStr = manager.getProperty(cname + ".level"); String levelStr = manager.getProperty(cname + ".level");
try { try {
if (levelStr != null) { if (levelStr != null) {
Level l = Level.parse(levelStr); Level l = Level.parse(levelStr);
setLevel(l != null ? l : Level.ALL); setLevel(l != null ? l : Level.ALL);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String filterStr = manager.getProperty(cname + ".filter"); String filterStr = manager.getProperty(cname + ".filter");
try { try {
if (filterStr != null) { if (filterStr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterStr); Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterStr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFilter((Filter) clz.getDeclaredConstructor().newInstance()); setFilter((Filter) clz.getDeclaredConstructor().newInstance());
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String formatterStr = manager.getProperty(cname + ".formatter"); String formatterStr = manager.getProperty(cname + ".formatter");
try { try {
if (formatterStr != null) { if (formatterStr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterStr); Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterStr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance()); setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
if (getFormatter() == null) { if (getFormatter() == null) {
setFormatter(new SimpleFormatter()); setFormatter(new SimpleFormatter());
} }
String encodingStr = manager.getProperty(cname + ".encoding"); String encodingStr = manager.getProperty(cname + ".encoding");
try { try {
if (encodingStr != null) { if (encodingStr != null) {
setEncoding(encodingStr); setEncoding(encodingStr);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
String denyRegxStr = manager.getProperty(cname + ".denyregx"); String denyRegxStr = manager.getProperty(cname + ".denyregx");
try { try {
if (denyRegxStr != null && !denyRegxStr.trim().isEmpty()) { if (denyRegxStr != null && !denyRegxStr.trim().isEmpty()) {
denyRegx = Pattern.compile(denyRegxStr); denyRegx = Pattern.compile(denyRegxStr);
} }
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
} }
@Override @Override
public void publish(LogRecord log) { public void publish(LogRecord log) {
if (!isLoggable(log)) { if (!isLoggable(log)) {
return; return;
} }
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) { if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
return; return;
} }
if (log.getSourceClassName() != null) { if (log.getSourceClassName() != null) {
StackTraceElement[] ses = new Throwable().getStackTrace(); StackTraceElement[] ses = new Throwable().getStackTrace();
for (int i = 2; i < ses.length; i++) { for (int i = 2; i < ses.length; i++) {
if (ses[i].getClassName().startsWith("java.util.logging")) { if (ses[i].getClassName().startsWith("java.util.logging")) {
continue; continue;
} }
log.setSourceClassName(ses[i].getClassName()); log.setSourceClassName(ses[i].getClassName());
log.setSourceMethodName(ses[i].getMethodName()); log.setSourceMethodName(ses[i].getMethodName());
break; break;
} }
} }
String rawTag = tagDateFormat == null String rawTag = tagDateFormat == null
? tag ? tag
: Times.formatTime(tagDateFormat, -1, log.getInstant().toEpochMilli()); : Times.formatTime(tagDateFormat, -1, log.getInstant().toEpochMilli());
fillLogRecord(log); fillLogRecord(log);
logqueue.offer(new SearchLogRecord(rawTag, log)); logqueue.offer(new SearchLogRecord(rawTag, log));
} }
@Override @Override
public void flush() { public void flush() {
// do nothing // do nothing
} }
@Override @Override
public void close() throws SecurityException { public void close() throws SecurityException {
// do nothing // do nothing
} }
@Entity @Entity
@Table(name = DEFAULT_TABLE_NAME) @Table(name = DEFAULT_TABLE_NAME)
@DistributeTable(strategy = SearchLogRecord.TableStrategy.class) @DistributeTable(strategy = SearchLogRecord.TableStrategy.class)
public static class SearchLogRecord { public static class SearchLogRecord {
@Id @Id
@ConvertColumn(index = 1) @ConvertColumn(index = 1)
@SearchColumn(options = "false") @SearchColumn(options = "false")
public String logid; public String logid;
@ConvertColumn(index = 2) @ConvertColumn(index = 2)
@SearchColumn(options = "false") @SearchColumn(options = "false")
public String level; public String level;
@ConvertColumn(index = 3) @ConvertColumn(index = 3)
@SearchColumn(date = true) @SearchColumn(date = true)
public long timestamp; public long timestamp;
@ConvertColumn(index = 4) @ConvertColumn(index = 4)
@SearchColumn(options = "false") @SearchColumn(options = "false")
public String traceid; public String traceid;
@ConvertColumn(index = 5) @ConvertColumn(index = 5)
public String threadName; public String threadName;
@ConvertColumn(index = 6) @ConvertColumn(index = 6)
@SearchColumn(text = true, options = "offsets") @SearchColumn(text = true, options = "offsets")
public String loggerName; public String loggerName;
@ConvertColumn(index = 7) @ConvertColumn(index = 7)
@SearchColumn(text = true, options = "offsets") @SearchColumn(text = true, options = "offsets")
public String methodName; public String methodName;
@ConvertColumn(index = 8) @ConvertColumn(index = 8)
@SearchColumn(text = true, options = "offsets") // , analyzer = "ik_max_word" @SearchColumn(text = true, options = "offsets") // , analyzer = "ik_max_word"
public String message; // log.message +"\r\n"+ log.thrown public String message; // log.message +"\r\n"+ log.thrown
@Transient @Transient
@ConvertDisabled @ConvertDisabled
LogRecord rawLog; LogRecord rawLog;
@Transient @Transient
@ConvertDisabled @ConvertDisabled
String rawTag; String rawTag;
public SearchLogRecord() {} public SearchLogRecord() {}
protected SearchLogRecord(String tag, LogRecord log) { protected SearchLogRecord(String tag, LogRecord log) {
this.rawLog = log; this.rawLog = log;
this.rawTag = tag; this.rawTag = tag;
this.threadName = Thread.currentThread().getName(); this.threadName = Thread.currentThread().getName();
this.traceid = LoggingBaseHandler.traceEnable && Traces.enable() ? Traces.currentTraceid() : null; this.traceid = LoggingBaseHandler.traceEnable && Traces.enable() ? Traces.currentTraceid() : null;
String msg = log.getMessage(); String msg = log.getMessage();
if (log.getThrown() != null) { if (log.getThrown() != null) {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw); PrintWriter pw = new PrintWriter(sw);
pw.println(); pw.println();
log.getThrown().printStackTrace(pw); log.getThrown().printStackTrace(pw);
pw.close(); pw.close();
String throwable = sw.toString(); String throwable = sw.toString();
this.message = (msg != null && !msg.isEmpty()) ? (msg + "\r\n" + throwable) : throwable; this.message = (msg != null && !msg.isEmpty()) ? (msg + "\r\n" + throwable) : throwable;
} else { } else {
this.message = msg; this.message = msg;
} }
this.level = log.getLevel().toString(); this.level = log.getLevel().toString();
this.loggerName = log.getLoggerName(); this.loggerName = log.getLoggerName();
this.methodName = log.getSourceClassName() + " " + log.getSourceMethodName(); this.methodName = log.getSourceClassName() + " " + log.getSourceMethodName();
this.timestamp = log.getInstant().toEpochMilli(); this.timestamp = log.getInstant().toEpochMilli();
this.logid = Times.format36time(timestamp) + "_" + Utility.uuid(); this.logid = Times.format36time(timestamp) + "_" + Utility.uuid();
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
public static class TableStrategy implements DistributeTableStrategy<SearchLogRecord> { public static class TableStrategy implements DistributeTableStrategy<SearchLogRecord> {
@Override @Override
public String getTable(String table, SearchLogRecord bean) { public String getTable(String table, SearchLogRecord bean) {
return bean.rawTag; return bean.rawTag;
} }
@Override @Override
public String getTable(String table, Serializable primary) { public String getTable(String table, Serializable primary) {
throw new UnsupportedOperationException("Not supported yet."); throw new UnsupportedOperationException("Not supported yet.");
} }
@Override @Override
public String[] getTables(String table, FilterNode node) { public String[] getTables(String table, FilterNode node) {
throw new UnsupportedOperationException("Not supported yet."); throw new UnsupportedOperationException("Not supported yet.");
} }
} }
} }
} }

View File

@@ -24,156 +24,156 @@ import org.redkale.util.Environment;
*/ */
public abstract class ModuleEngine { public abstract class ModuleEngine {
protected final Logger logger = Logger.getLogger(getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(getClass().getSimpleName());
protected final Application application; protected final Application application;
protected final ResourceFactory resourceFactory; protected final ResourceFactory resourceFactory;
protected final Environment environment; protected final Environment environment;
public ModuleEngine(Application application) { public ModuleEngine(Application application) {
this.application = application; this.application = application;
this.resourceFactory = Objects.requireNonNull(application.resourceFactory); this.resourceFactory = Objects.requireNonNull(application.resourceFactory);
this.environment = Objects.requireNonNull(application.getEnvironment()); this.environment = Objects.requireNonNull(application.getEnvironment());
} }
/** /**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
* *
* @param path 配置项路径 * @param path 配置项路径
* @param key 配置项名称 * @param key 配置项名称
* @param val1 配置项原值 * @param val1 配置项原值
* @param val2 配置项新值 * @param val2 配置项新值
* @return MergeEnum * @return MergeEnum
*/ */
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
return null; return null;
} }
/** /**
* 动态扩展类的方法 * 动态扩展类的方法
* *
* @param remote 是否远程模式 * @param remote 是否远程模式
* @param serviceClass 类 * @param serviceClass 类
* @return 方法动态扩展器 * @return 方法动态扩展器
*/ */
public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) {
return null; return null;
} }
/** 进入Application.init方法时被调用 此时状态: 1、远程配置项未获取 2、WorkExecutor未初始化 */ /** 进入Application.init方法时被调用 此时状态: 1、远程配置项未获取 2、WorkExecutor未初始化 */
public void onAppPreInit() { public void onAppPreInit() {
// do nothing // do nothing
} }
/** 结束Application.init方法前被调用 */ /** 结束Application.init方法前被调用 */
public void onAppPostInit() { public void onAppPostInit() {
// do nothing // do nothing
} }
/** 进入Application.start方法被调用 */ /** 进入Application.start方法被调用 */
public void onAppPreStart() { public void onAppPreStart() {
// do nothing // do nothing
} }
/** 结束Application.start方法前被调用 */ /** 结束Application.start方法前被调用 */
public void onAppPostStart() { public void onAppPostStart() {
// do nothing // do nothing
} }
/** /**
* 配置项加载后被调用 * 配置项加载后被调用
* *
* @param allProps 配置项全量 * @param allProps 配置项全量
*/ */
public void onEnvironmentLoaded(Properties allProps) { public void onEnvironmentLoaded(Properties allProps) {
// do nothing // do nothing
} }
/** /**
* 配置项变更时被调用 * 配置项变更时被调用
* *
* @param namespace 命名空间 * @param namespace 命名空间
* @param events 变更项 * @param events 变更项
*/ */
public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) { public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
// do nothing // do nothing
} }
/** Application 在运行Compile前调用 */ /** Application 在运行Compile前调用 */
public void onPreCompile() { public void onPreCompile() {
// do nothing // do nothing
} }
/** Application 在运行Compile后调用 */ /** Application 在运行Compile后调用 */
public void onPostCompile() { public void onPostCompile() {
// do nothing // do nothing
} }
/** 服务全部启动前被调用 */ /** 服务全部启动前被调用 */
public void onServersPreStart() { public void onServersPreStart() {
// do nothing // do nothing
} }
/** 服务全部启动后被调用 */ /** 服务全部启动后被调用 */
public void onServersPostStart() { public void onServersPostStart() {
// do nothing // do nothing
} }
/** /**
* 执行Service.init方法前被调用 * 执行Service.init方法前被调用
* *
* @param service Service * @param service Service
*/ */
public void onServicePreInit(Service service) { public void onServicePreInit(Service service) {
// do nothing // do nothing
} }
/** /**
* 执行Service.init方法后被调用 * 执行Service.init方法后被调用
* *
* @param service Service * @param service Service
*/ */
public void onServicePostInit(Service service) { public void onServicePostInit(Service service) {
// do nothing // do nothing
} }
/** /**
* 执行Service.destroy方法前被调用 * 执行Service.destroy方法前被调用
* *
* @param service Service * @param service Service
*/ */
public void onServicePreDestroy(Service service) { public void onServicePreDestroy(Service service) {
// do nothing // do nothing
} }
/** /**
* 执行Service.destroy方法后被调用 * 执行Service.destroy方法后被调用
* *
* @param service Service * @param service Service
*/ */
public void onServicePostDestroy(Service service) { public void onServicePostDestroy(Service service) {
// do nothing // do nothing
} }
/** 服务全部停掉前被调用 */ /** 服务全部停掉前被调用 */
public void onServersPreStop() { public void onServersPreStop() {
// do nothing // do nothing
} }
/** 服务全部停掉后被调用 */ /** 服务全部停掉后被调用 */
public void onServersPostStop() { public void onServersPostStop() {
// do nothing // do nothing
} }
/** 进入Application.shutdown方法被调用 */ /** 进入Application.shutdown方法被调用 */
public void onAppPreShutdown() { public void onAppPreShutdown() {
// do nothing // do nothing
} }
/** 结束Application.shutdown方法前被调用 */ /** 结束Application.shutdown方法前被调用 */
public void onAppPostShutdown() { public void onAppPostShutdown() {
// do nothing // do nothing
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -14,23 +14,23 @@ package org.redkale.boot;
*/ */
public class NodeInterceptor { public class NodeInterceptor {
/** /**
* * Server.start之前调用 <br> * * Server.start之前调用 <br>
* NodeServer.start的部署是先执行NodeInterceptor.preStart再执行 Server.start 方法 * NodeServer.start的部署是先执行NodeInterceptor.preStart再执行 Server.start 方法
* *
* @param server NodeServer * @param server NodeServer
*/ */
public void preStart(NodeServer server) { public void preStart(NodeServer server) {
// do nothing // do nothing
} }
/** /**
* Server.shutdown之前调用 <br> * Server.shutdown之前调用 <br>
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown再执行 Server.shutdown 方法 * NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown再执行 Server.shutdown 方法
* *
* @param server NodeServer * @param server NodeServer
*/ */
public void preShutdown(NodeServer server) { public void preShutdown(NodeServer server) {
// do nothing // do nothing
} }
} }

View File

@@ -19,5 +19,5 @@ import java.lang.annotation.*;
@Documented @Documented
public @interface NodeProtocol { public @interface NodeProtocol {
String value(); String value();
} }

File diff suppressed because it is too large Load Diff

View File

@@ -25,159 +25,159 @@ import org.redkale.util.*;
@NodeProtocol("SNCP") @NodeProtocol("SNCP")
public class NodeSncpServer extends NodeServer { public class NodeSncpServer extends NodeServer {
protected final SncpServer sncpServer; protected final SncpServer sncpServer;
private NodeSncpServer(Application application, AnyValue serconf) { private NodeSncpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf)); super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server; this.sncpServer = (SncpServer) this.server;
} }
public static NodeServer createNodeServer(Application application, AnyValue serconf) { public static NodeServer createNodeServer(Application application, AnyValue serconf) {
return new NodeSncpServer(application, serconf); return new NodeSncpServer(application, serconf);
} }
private static Server createServer(Application application, AnyValue serconf) { private static Server createServer(Application application, AnyValue serconf) {
return new SncpServer( return new SncpServer(
application, application,
application.getStartTime(), application.getStartTime(),
serconf, serconf,
application.getResourceFactory().createChild()); application.getResourceFactory().createChild());
} }
@Override @Override
public InetSocketAddress getSocketAddress() { public InetSocketAddress getSocketAddress() {
return sncpServer == null ? null : sncpServer.getSocketAddress(); return sncpServer == null ? null : sncpServer.getSocketAddress();
} }
@Override @Override
public void init(AnyValue config) throws Exception { public void init(AnyValue config) throws Exception {
super.init(config); super.init(config);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
if (sncpServer == null) { if (sncpServer == null) {
return; // 调试时server才可能为null return; // 调试时server才可能为null
} }
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
List<SncpServlet> servlets = sncpServer.getSncpServlets(); List<SncpServlet> servlets = sncpServer.getSncpServlets();
Collections.sort(servlets); Collections.sort(servlets);
int maxTypeLength = 0; int maxTypeLength = 0;
int maxNameLength = 0; int maxNameLength = 0;
for (SncpServlet en : servlets) { for (SncpServlet en : servlets) {
maxNameLength = Math.max(maxNameLength, en.getResourceName().length() + 1); maxNameLength = Math.max(maxNameLength, en.getResourceName().length() + 1);
maxTypeLength = maxTypeLength =
Math.max(maxTypeLength, en.getResourceType().getName().length()); Math.max(maxTypeLength, en.getResourceType().getName().length());
} }
for (SncpServlet en : servlets) { for (SncpServlet en : servlets) {
if (sb != null) { if (sb != null) {
sb.append("Load ") sb.append("Load ")
.append(toSimpleString(en, maxTypeLength, maxNameLength)) .append(toSimpleString(en, maxTypeLength, maxNameLength))
.append(LINE_SEPARATOR); .append(LINE_SEPARATOR);
} }
} }
if (sb != null && sb.length() > 0) { if (sb != null && sb.length() > 0) {
logger.log(Level.FINE, sb.toString()); logger.log(Level.FINE, sb.toString());
} }
} }
private StringBuilder toSimpleString(SncpServlet servlet, int maxTypeLength, int maxNameLength) { private StringBuilder toSimpleString(SncpServlet servlet, int maxTypeLength, int maxNameLength) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
Class serviceType = servlet.getResourceType(); Class serviceType = servlet.getResourceType();
String serviceName = servlet.getResourceName(); String serviceName = servlet.getResourceName();
int size = servlet.getActionSize(); int size = servlet.getActionSize();
sb.append(SncpServlet.class.getSimpleName()).append(" (type=").append(serviceType.getName()); sb.append(SncpServlet.class.getSimpleName()).append(" (type=").append(serviceType.getName());
int len = maxTypeLength - serviceType.getName().length(); int len = maxTypeLength - serviceType.getName().length();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
sb.append(' '); sb.append(' ');
} }
sb.append(", serviceid=") sb.append(", serviceid=")
.append(servlet.getServiceid()) .append(servlet.getServiceid())
.append(", name='") .append(", name='")
.append(serviceName) .append(serviceName)
.append("'"); .append("'");
for (int i = 0; i < maxNameLength - serviceName.length(); i++) { for (int i = 0; i < maxNameLength - serviceName.length(); i++) {
sb.append(' '); sb.append(' ');
} }
sb.append(", actions.size=").append(size > 9 ? "" : " ").append(size).append(")"); sb.append(", actions.size=").append(size > 9 ? "" : " ").append(size).append(")");
return sb; return sb;
} }
@Override @Override
public boolean isSNCP() { public boolean isSNCP() {
return true; return true;
} }
public SncpServer getSncpServer() { public SncpServer getSncpServer() {
return sncpServer; return sncpServer;
} }
@Override @Override
protected void loadFilter(ClassFilter<? extends Filter> filterFilter) throws Exception { protected void loadFilter(ClassFilter<? extends Filter> filterFilter) throws Exception {
if (sncpServer != null) { if (sncpServer != null) {
loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter); loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
} }
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter)
throws Exception { throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys()); List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
for (FilterEntry<? extends Filter> entry : list) { for (FilterEntry<? extends Filter> entry : list) {
Class<SncpFilter> clazz = (Class<SncpFilter>) entry.getType(); Class<SncpFilter> clazz = (Class<SncpFilter>) entry.getType();
if (Utility.isAbstractOrInterface(clazz)) { if (Utility.isAbstractOrInterface(clazz)) {
continue; continue;
} }
if (entry.isExpect()) { // 跳过不自动加载的Filter if (entry.isExpect()) { // 跳过不自动加载的Filter
continue; continue;
} }
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
final SncpFilter filter = clazz.getDeclaredConstructor().newInstance(); final SncpFilter filter = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(filter, this); resourceFactory.inject(filter, this);
AnyValueWriter filterConf = (AnyValueWriter) entry.getProperty(); AnyValueWriter filterConf = (AnyValueWriter) entry.getProperty();
this.sncpServer.addSncpFilter(filter, filterConf); this.sncpServer.addSncpFilter(filter, filterConf);
if (sb != null) { if (sb != null) {
sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR); sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR);
} }
} }
if (sb != null && sb.length() > 0) { if (sb != null && sb.length() > 0) {
logger.log(Level.INFO, sb.toString()); logger.log(Level.INFO, sb.toString());
} }
} }
@Override @Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception { protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName()); RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
if (!application.isSingletonMode()) { if (!application.isSingletonMode()) {
this.servletServices.stream() this.servletServices.stream()
.filter(x -> x.getClass().getAnnotation(Local.class) == null) // Local模式的Service不生成SncpServlet .filter(x -> x.getClass().getAnnotation(Local.class) == null) // Local模式的Service不生成SncpServlet
.forEach(x -> { .forEach(x -> {
SncpServlet servlet = sncpServer.addSncpServlet(x); SncpServlet servlet = sncpServer.addSncpServlet(x);
dynServletMap.put(x, servlet); dynServletMap.put(x, servlet);
String mq = Sncp.getResourceMQ(x); String mq = Sncp.getResourceMQ(x);
if (mq != null) { if (mq != null) {
MessageAgent agent = MessageAgent agent =
application.getResourceFactory().find(mq, MessageAgent.class); application.getResourceFactory().find(mq, MessageAgent.class);
agent.putService(this, x, servlet); agent.putService(this, x, servlet);
} }
}); });
} }
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() { protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter( return createClassFilter(
null, null,
null, null,
SncpFilter.class, SncpFilter.class,
new Class[] {org.redkale.watch.WatchFilter.class}, new Class[] {org.redkale.watch.WatchFilter.class},
null, null,
"filters", "filters",
"filter"); "filter");
} }
@Override @Override
protected ClassFilter<Servlet> createServletClassFilter() { protected ClassFilter<Servlet> createServletClassFilter() {
return null; return null;
} }
} }

View File

@@ -17,36 +17,36 @@ import org.redkale.watch.*;
@NodeProtocol("WATCH") @NodeProtocol("WATCH")
public class NodeWatchServer extends NodeHttpServer { public class NodeWatchServer extends NodeHttpServer {
public NodeWatchServer(Application application, AnyValue serconf) { public NodeWatchServer(Application application, AnyValue serconf) {
super(application, serconf); super(application, serconf);
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected ClassFilter<Service> createServiceClassFilter() { protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter( return createClassFilter(
this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service"); this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() { protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter"); return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected ClassFilter<Servlet> createServletClassFilter() { protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet"); return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
} }
@Override @Override
protected List<ClassFilter> createOtherClassFilters() { protected List<ClassFilter> createOtherClassFilters() {
return null; // 不调用 super.createOtherClassFilters() return null; // 不调用 super.createOtherClassFilters()
} }
@Override @Override
public boolean isWATCH() { public boolean isWATCH() {
return true; return true;
} }
} }

View File

@@ -23,123 +23,123 @@ import org.redkale.util.Utility;
*/ */
public class PrepareCompiler { public class PrepareCompiler {
// public static void main(String[] args) throws Exception { // public static void main(String[] args) throws Exception {
// new PrepareCompiler().run(); // new PrepareCompiler().run();
// } // }
public Application run() throws Exception { public Application run() throws Exception {
// 必须设置redkale.resource.skip.check=true // 必须设置redkale.resource.skip.check=true
// 因redkale-maven-plugin的maven-core依赖jsr250会覆盖redkale的javax.annotation.Resource导致无法识别Resource.required方法 // 因redkale-maven-plugin的maven-core依赖jsr250会覆盖redkale的javax.annotation.Resource导致无法识别Resource.required方法
System.setProperty("redkale.resource.skip.check", "true"); System.setProperty("redkale.resource.skip.check", "true");
final Application application = new Application(AppConfig.create(false, true)); final Application application = new Application(AppConfig.create(false, true));
application.init(); application.init();
application.onPreCompile(); application.onPreCompile();
application.start(); application.start();
final boolean hasSncp = application.getNodeServers().stream() final boolean hasSncp = application.getNodeServers().stream()
.filter(NodeSncpServer.class::isInstance) .filter(NodeSncpServer.class::isInstance)
.findFirst() .findFirst()
.isPresent(); .isPresent();
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class); final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class);
final ClassFilter<?> entityFilter2 = final ClassFilter<?> entityFilter2 =
new ClassFilter(application.getClassLoader(), javax.persistence.Entity.class, Object.class); new ClassFilter(application.getClassLoader(), javax.persistence.Entity.class, Object.class);
final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class); final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class);
final ClassFilter<?> beanFilter2 = final ClassFilter<?> beanFilter2 =
new ClassFilter(application.getClassLoader(), org.redkale.util.Bean.class, Object.class); new ClassFilter(application.getClassLoader(), org.redkale.util.Bean.class, Object.class);
final ClassFilter<?> filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class); final ClassFilter<?> filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class);
application.loadClassByFilters(entityFilter, beanFilter, filterFilter); application.loadClassByFilters(entityFilter, beanFilter, filterFilter);
for (FilterEntry en : entityFilter.getFilterEntrys()) { for (FilterEntry en : entityFilter.getFilterEntrys()) {
Class clz = en.getType(); Class clz = en.getType();
if (Utility.isAbstractOrInterface(clz)) { if (Utility.isAbstractOrInterface(clz)) {
continue; continue;
} }
try { try {
List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class); List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class);
dataSources.forEach(source -> source.compile(clz)); dataSources.forEach(source -> source.compile(clz));
// application.dataSources.forEach(source -> source.compile(clz)); // application.dataSources.forEach(source -> source.compile(clz));
JsonFactory.root().loadEncoder(clz); JsonFactory.root().loadEncoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadEncoder(clz); BsonFactory.root().loadEncoder(clz);
} }
Decodeable decoder = JsonFactory.root().loadDecoder(clz); Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadDecoder(clz); BsonFactory.root().loadDecoder(clz);
} }
decoder.convertFrom(new JsonReader("{}")); decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段 } catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
} }
} }
for (FilterEntry en : entityFilter2.getFilterEntrys()) { for (FilterEntry en : entityFilter2.getFilterEntrys()) {
Class clz = en.getType(); Class clz = en.getType();
if (Utility.isAbstractOrInterface(clz)) { if (Utility.isAbstractOrInterface(clz)) {
continue; continue;
} }
try { try {
List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class); List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class);
dataSources.forEach(source -> source.compile(clz)); dataSources.forEach(source -> source.compile(clz));
// application.dataSources.forEach(source -> source.compile(clz)); // application.dataSources.forEach(source -> source.compile(clz));
JsonFactory.root().loadEncoder(clz); JsonFactory.root().loadEncoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadEncoder(clz); BsonFactory.root().loadEncoder(clz);
} }
Decodeable decoder = JsonFactory.root().loadDecoder(clz); Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadDecoder(clz); BsonFactory.root().loadDecoder(clz);
} }
decoder.convertFrom(new JsonReader("{}")); decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段 } catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
} }
} }
for (FilterEntry en : beanFilter.getFilterEntrys()) { for (FilterEntry en : beanFilter.getFilterEntrys()) {
Class clz = en.getType(); Class clz = en.getType();
if (Utility.isAbstractOrInterface(clz)) { if (Utility.isAbstractOrInterface(clz)) {
continue; continue;
} }
try { try {
JsonFactory.root().loadEncoder(clz); JsonFactory.root().loadEncoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadEncoder(clz); BsonFactory.root().loadEncoder(clz);
} }
Decodeable decoder = JsonFactory.root().loadDecoder(clz); Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadDecoder(clz); BsonFactory.root().loadDecoder(clz);
} }
decoder.convertFrom(new JsonReader("{}")); decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段 } catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
} }
} }
for (FilterEntry en : beanFilter2.getFilterEntrys()) { for (FilterEntry en : beanFilter2.getFilterEntrys()) {
Class clz = en.getType(); Class clz = en.getType();
if (Utility.isAbstractOrInterface(clz)) { if (Utility.isAbstractOrInterface(clz)) {
continue; continue;
} }
try { try {
JsonFactory.root().loadEncoder(clz); JsonFactory.root().loadEncoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadEncoder(clz); BsonFactory.root().loadEncoder(clz);
} }
Decodeable decoder = JsonFactory.root().loadDecoder(clz); Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) { if (hasSncp) {
BsonFactory.root().loadDecoder(clz); BsonFactory.root().loadDecoder(clz);
} }
decoder.convertFrom(new JsonReader("{}")); decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段 } catch (Exception e) { // JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
} }
} }
for (FilterEntry en : filterFilter.getFilterEntrys()) { for (FilterEntry en : filterFilter.getFilterEntrys()) {
Class clz = en.getType(); Class clz = en.getType();
if (Utility.isAbstractOrInterface(clz)) { if (Utility.isAbstractOrInterface(clz)) {
continue; continue;
} }
try { try {
FilterNodeBean.load(clz); FilterNodeBean.load(clz);
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} }
} }
application.onPostCompile(); application.onPostCompile();
application.shutdown(); application.shutdown();
return application; return application;
} }
} }

View File

@@ -12,11 +12,11 @@ import org.redkale.watch.WatchService;
/** @author zhangjx */ /** @author zhangjx */
public abstract class AbstractWatchService extends AbstractService implements WatchService { public abstract class AbstractWatchService extends AbstractService implements WatchService {
/** 缺少参数 */ /** 缺少参数 */
@Comment("缺少参数") @Comment("缺少参数")
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001; public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
/** 执行异常 */ /** 执行异常 */
@Comment("执行异常") @Comment("执行异常")
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002; public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
} }

View File

@@ -16,69 +16,69 @@ import org.redkale.service.RetResult;
@RestService(name = "filter", catalog = "watch", repair = false) @RestService(name = "filter", catalog = "watch", repair = false)
public class FilterWatchService extends AbstractWatchService { public class FilterWatchService extends AbstractWatchService {
@Comment("Filter类名不存在") @Comment("Filter类名不存在")
public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002; public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002;
@Comment("Filter类名不合法") @Comment("Filter类名不合法")
public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003; public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003;
@Comment("Filter类名已存在") @Comment("Filter类名已存在")
public static final int RET_FILTER_EXISTS = 1601_0004; public static final int RET_FILTER_EXISTS = 1601_0004;
@Comment("Filter的JAR包不存在") @Comment("Filter的JAR包不存在")
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005; public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
@Resource @Resource
protected Application application; protected Application application;
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter") @RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
public RetResult addFilter( public RetResult addFilter(
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar,
@RestParam(name = "server", comment = "Server节点名") final String serverName, @RestParam(name = "server", comment = "Server节点名") final String serverName,
@RestParam(name = "type", comment = "Filter类名") final String filterType) @RestParam(name = "type", comment = "Filter类名") final String filterType)
throws IOException { throws IOException {
if (filterType == null) { if (filterType == null) {
return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")"); return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
} }
if (jar == null) { if (jar == null) {
return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file"); return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
} }
List<NodeServer> nodes = application.getNodeServers(); List<NodeServer> nodes = application.getNodeServers();
for (NodeServer node : nodes) { for (NodeServer node : nodes) {
if (node.getServer().containsFilter(filterType)) { if (node.getServer().containsFilter(filterType)) {
return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists"); return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
} }
} }
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test1", auth = false, comment = "预留") @RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() { public RetResult test1() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test2", auth = false, comment = "预留") @RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() { public RetResult test2() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test3", auth = false, comment = "预留") @RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() { public RetResult test3() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test4", auth = false, comment = "预留") @RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() { public RetResult test4() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test5", auth = false, comment = "预留") @RestMapping(name = "test5", auth = false, comment = "预留")
public RetResult test5() { public RetResult test5() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test6", auth = false, comment = "预留") @RestMapping(name = "test6", auth = false, comment = "预留")
public RetResult test6() { public RetResult test6() {
return RetResult.success(); return RetResult.success();
} }
} }

View File

@@ -19,99 +19,99 @@ import org.redkale.service.RetResult;
@RestService(name = "server", catalog = "watch", repair = false) @RestService(name = "server", catalog = "watch", repair = false)
public class ServerWatchService extends AbstractWatchService { public class ServerWatchService extends AbstractWatchService {
@Comment("不存在的Server节点") @Comment("不存在的Server节点")
public static final int RET_SERVER_NOT_EXISTS = 1602_0001; public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
@Comment("更改Server监听地址端口失败") @Comment("更改Server监听地址端口失败")
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002; public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
@Resource @Resource
protected Application application; protected Application application;
@RestMapping(name = "info", comment = "单个Server信息查询") @RestMapping(name = "info", comment = "单个Server信息查询")
public RetResult info(@RestParam(name = "#port:") final int port) { public RetResult info(@RestParam(name = "#port:") final int port) {
Stream<NodeServer> stream = application.getNodeServers().stream(); Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port) NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
if (node == null) { if (node == null) {
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found"); return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
} }
return new RetResult(formatToMap(node)); return new RetResult(formatToMap(node));
} }
@RestMapping(name = "infos", comment = "Server信息查询") @RestMapping(name = "infos", comment = "Server信息查询")
public RetResult infos() { public RetResult infos() {
Map<String, Object> rs = new LinkedHashMap<>(); Map<String, Object> rs = new LinkedHashMap<>();
for (NodeServer ns : application.getNodeServers()) { for (NodeServer ns : application.getNodeServers()) {
Server server = ns.getServer(); Server server = ns.getServer();
rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns)); rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns));
} }
return new RetResult(rs); return new RetResult(rs);
} }
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口") @RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
public RetResult changeAddress( public RetResult changeAddress(
@RestParam(name = "#port:") final int oldport, @RestParam(name = "#port:") final int oldport,
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newhost:") final String newhost,
@RestParam(name = "#newport:") final int newport) { @RestParam(name = "#newport:") final int newport) {
if (oldport < 1) { if (oldport < 1) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
} }
if (newport < 1) { if (newport < 1) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
} }
Stream<NodeServer> stream = application.getNodeServers().stream(); Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport) NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
if (node == null) { if (node == null) {
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found"); return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
} }
final Server server = node.getServer(); final Server server = node.getServer();
InetSocketAddress newAddr = new InetSocketAddress( InetSocketAddress newAddr = new InetSocketAddress(
newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport); newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
try { try {
server.changeAddress(application, newAddr); server.changeAddress(application, newAddr);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeAddress error"); return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeAddress error");
} }
return RetResult.success(); return RetResult.success();
} }
private Map<String, Object> formatToMap(NodeServer node) { private Map<String, Object> formatToMap(NodeServer node) {
Server server = node.getServer(); Server server = node.getServer();
Map<String, Object> rs = new LinkedHashMap<>(); Map<String, Object> rs = new LinkedHashMap<>();
String protocol = server.getNetprotocol(); String protocol = server.getNetprotocol();
if (node instanceof NodeSncpServer) { if (node instanceof NodeSncpServer) {
protocol += "/SNCP"; protocol += "/SNCP";
} else if (node instanceof NodeWatchServer) { } else if (node instanceof NodeWatchServer) {
protocol += "/WATCH"; protocol += "/WATCH";
} else if (node instanceof NodeHttpServer) { } else if (node instanceof NodeHttpServer) {
protocol += "/HTTP"; protocol += "/HTTP";
} else { } else {
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class); NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
protocol += "/" + np.value(); protocol += "/" + np.value();
} }
rs.put("name", server.getName()); rs.put("name", server.getName());
rs.put("protocol", protocol); rs.put("protocol", protocol);
rs.put("address", server.getSocketAddress()); rs.put("address", server.getSocketAddress());
rs.put("backlog", server.getBacklog()); rs.put("backlog", server.getBacklog());
rs.put("bufferCapacity", server.getBufferCapacity()); rs.put("bufferCapacity", server.getBufferCapacity());
rs.put("bufferPoolSize", server.getBufferPoolSize()); rs.put("bufferPoolSize", server.getBufferPoolSize());
rs.put( rs.put(
"charset", "charset",
server.getCharset() == null ? "UTF-8" : server.getCharset().name()); server.getCharset() == null ? "UTF-8" : server.getCharset().name());
rs.put("maxbody", server.getMaxBody()); rs.put("maxbody", server.getMaxBody());
rs.put("maxconns", server.getMaxConns()); rs.put("maxconns", server.getMaxConns());
rs.put("serverStartTime", server.getServerStartTime()); rs.put("serverStartTime", server.getServerStartTime());
rs.put("responsePoolSize", server.getResponsePoolSize()); rs.put("responsePoolSize", server.getResponsePoolSize());
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds()); rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());
rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds()); rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds());
rs.put("createConnectionCount", server.getCreateConnectionCount()); rs.put("createConnectionCount", server.getCreateConnectionCount());
rs.put("livingConnectionCount", server.getLivingConnectionCount()); rs.put("livingConnectionCount", server.getLivingConnectionCount());
rs.put("closedConnectionCount", server.getClosedConnectionCount()); rs.put("closedConnectionCount", server.getClosedConnectionCount());
return rs; return rs;
} }
} }

View File

@@ -22,241 +22,241 @@ import org.redkale.service.RetResult;
@RestService(name = "service", catalog = "watch", repair = false) @RestService(name = "service", catalog = "watch", repair = false)
public class ServiceWatchService extends AbstractWatchService { public class ServiceWatchService extends AbstractWatchService {
@Comment("没有找到目标Service") @Comment("没有找到目标Service")
public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001; public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001;
@Resource @Resource
protected Application application; protected Application application;
@RestConvert(type = void.class) @RestConvert(type = void.class)
@RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容") @RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容")
public RetResult setField( public RetResult setField(
@RestParam(name = "name", comment = "Service的资源名") String name, @RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type, @RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field, @RestParam(name = "field", comment = "字段名") String field,
@RestParam(name = "value", comment = "字段值") String value) { @RestParam(name = "value", comment = "字段值") String value) {
if (name == null) { if (name == null) {
name = ""; name = "";
} }
if (type == null) { if (type == null) {
type = ""; type = "";
} }
if (field == null) { if (field == null) {
field = ""; field = "";
} }
type = type.trim(); type = type.trim();
field = field.trim(); field = field.trim();
if (type.isEmpty()) { if (type.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
} }
if (field.isEmpty()) { if (field.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
} }
Object dest = findService(name, type); Object dest = findService(name, type);
Class clazz = dest.getClass(); Class clazz = dest.getClass();
Throwable t = null; Throwable t = null;
try { try {
Field fieldObj = null; Field fieldObj = null;
do { do {
try { try {
fieldObj = clazz.getDeclaredField(field); fieldObj = clazz.getDeclaredField(field);
break; break;
} catch (Exception e) { } catch (Exception e) {
if (t == null) { if (t == null) {
t = e; t = e;
} }
} }
} while ((clazz = clazz.getSuperclass()) != Object.class); } while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) { if (fieldObj == null) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")"); return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
} }
fieldObj.setAccessible(true); fieldObj.setAccessible(true);
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value)); fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
return RetResult.success(); return RetResult.success();
} catch (Throwable t2) { } catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
} }
} }
@RestConvert(type = void.class) @RestConvert(type = void.class)
@RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容") @RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容")
public RetResult getField( public RetResult getField(
@RestParam(name = "name", comment = "Service的资源名") String name, @RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type, @RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field) { @RestParam(name = "field", comment = "字段名") String field) {
if (name == null) { if (name == null) {
name = ""; name = "";
} }
if (type == null) { if (type == null) {
type = ""; type = "";
} }
if (field == null) { if (field == null) {
field = ""; field = "";
} }
type = type.trim(); type = type.trim();
field = field.trim(); field = field.trim();
if (type.isEmpty()) { if (type.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
} }
if (field.isEmpty()) { if (field.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
} }
Object dest = findService(name, type); Object dest = findService(name, type);
Class clazz = dest.getClass(); Class clazz = dest.getClass();
Throwable t = null; Throwable t = null;
try { try {
Field fieldObj = null; Field fieldObj = null;
do { do {
try { try {
fieldObj = clazz.getDeclaredField(field); fieldObj = clazz.getDeclaredField(field);
break; break;
} catch (Exception e) { } catch (Exception e) {
if (t == null) { if (t == null) {
t = e; t = e;
} }
} }
} while ((clazz = clazz.getSuperclass()) != Object.class); } while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) { if (fieldObj == null) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")"); return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
} }
fieldObj.setAccessible(true); fieldObj.setAccessible(true);
return new RetResult(fieldObj.get(dest)); return new RetResult(fieldObj.get(dest));
} catch (Throwable t2) { } catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
} }
} }
@RestConvert(type = void.class) @RestConvert(type = void.class)
@RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法") @RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法")
public RetResult runMethod( public RetResult runMethod(
@RestParam(name = "name", comment = "Service的资源名") String name, @RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type, @RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "method", comment = "Service的方法名") String method, @RestParam(name = "method", comment = "Service的方法名") String method,
@RestParam(name = "params", comment = "方法的参数值") List<String> params, @RestParam(name = "params", comment = "方法的参数值") List<String> params,
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) { @RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
if (name == null) { if (name == null) {
name = ""; name = "";
} }
if (type == null) { if (type == null) {
type = ""; type = "";
} }
if (method == null) { if (method == null) {
method = ""; method = "";
} }
type = type.trim(); type = type.trim();
method = method.trim(); method = method.trim();
if (type.isEmpty()) { if (type.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
} }
if (method.isEmpty()) { if (method.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
} }
Object dest = findService(name, type); Object dest = findService(name, type);
Class clazz = dest.getClass(); Class clazz = dest.getClass();
Throwable t = null; Throwable t = null;
final int paramcount = params == null ? 0 : params.size(); final int paramcount = params == null ? 0 : params.size();
if (paramtypes != null && paramcount != paramtypes.size()) { if (paramtypes != null && paramcount != paramtypes.size()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size"); return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
} }
try { try {
Method methodObj = null; Method methodObj = null;
do { do {
try { try {
for (Method m : clazz.getDeclaredMethods()) { for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equals(method) && m.getParameterCount() == paramcount) { if (m.getName().equals(method) && m.getParameterCount() == paramcount) {
boolean flag = true; boolean flag = true;
if (paramtypes != null) { if (paramtypes != null) {
Class[] pts = m.getParameterTypes(); Class[] pts = m.getParameterTypes();
for (int i = 0; i < pts.length; i++) { for (int i = 0; i < pts.length; i++) {
if (!pts[i].getName().endsWith(paramtypes.get(i))) { if (!pts[i].getName().endsWith(paramtypes.get(i))) {
flag = false; flag = false;
break; break;
} }
} }
} }
if (flag) { if (flag) {
methodObj = m; methodObj = m;
break; break;
} }
} }
} }
if (methodObj != null) { if (methodObj != null) {
break; break;
} }
} catch (Exception e) { } catch (Exception e) {
if (t == null) { if (t == null) {
t = e; t = e;
} }
} }
} while ((clazz = clazz.getSuperclass()) != Object.class); } while ((clazz = clazz.getSuperclass()) != Object.class);
if (methodObj == null) { if (methodObj == null) {
return new RetResult( return new RetResult(
RET_WATCH_RUN_EXCEPTION, RET_WATCH_RUN_EXCEPTION,
"run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t))
+ ")"); + ")");
} }
methodObj.setAccessible(true); methodObj.setAccessible(true);
if (paramcount < 1) { if (paramcount < 1) {
return new RetResult(methodObj.invoke(dest)); return new RetResult(methodObj.invoke(dest));
} }
Object[] paramObjs = new Object[paramcount]; Object[] paramObjs = new Object[paramcount];
Type[] pts = methodObj.getGenericParameterTypes(); Type[] pts = methodObj.getGenericParameterTypes();
for (int i = 0; i < paramObjs.length; i++) { for (int i = 0; i < paramObjs.length; i++) {
paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i)); paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i));
} }
return new RetResult(methodObj.invoke(dest, paramObjs)); return new RetResult(methodObj.invoke(dest, paramObjs));
} catch (Throwable t2) { } catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
} }
} }
protected Object findService(String name, String type) { protected Object findService(String name, String type) {
Object dest = null; Object dest = null;
for (NodeServer ns : application.getNodeServers()) { for (NodeServer ns : application.getNodeServers()) {
ResourceFactory resFactory = ns.getResourceFactory(); ResourceFactory resFactory = ns.getResourceFactory();
List list = resFactory.query((n, s) -> List list = resFactory.query((n, s) ->
name.equals(n) && s != null && s.getClass().getName().endsWith(type)); name.equals(n) && s != null && s.getClass().getName().endsWith(type));
if (list == null || list.isEmpty()) { if (list == null || list.isEmpty()) {
continue; continue;
} }
dest = list.get(0); dest = list.get(0);
} }
if (dest == null) { if (dest == null) {
return new RetResult( return new RetResult(
RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")"); RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
} }
return dest; return dest;
} }
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service") @RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
public RetResult loadService( public RetResult loadService(
@RestParam(name = "type", comment = "Service的类名") String type, @RestParam(name = "type", comment = "Service的类名") String type,
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar) { @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar) {
// 待开发 // 待开发
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "reloadService", auth = false, comment = "重新加载Service") @RestMapping(name = "reloadService", auth = false, comment = "重新加载Service")
public RetResult reloadService( public RetResult reloadService(
@RestParam(name = "name", comment = "Service的资源名") String name, @RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) { @RestParam(name = "type", comment = "Service的类名") String type) {
// 待开发 // 待开发
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "stopService", auth = false, comment = "动态停止Service") @RestMapping(name = "stopService", auth = false, comment = "动态停止Service")
public RetResult stopService( public RetResult stopService(
@RestParam(name = "name", comment = "Service的资源名") String name, @RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) { @RestParam(name = "type", comment = "Service的类名") String type) {
// 待开发 // 待开发
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "findService", auth = false, comment = "查找Service") @RestMapping(name = "findService", auth = false, comment = "查找Service")
public RetResult find( public RetResult find(
@RestParam(name = "name", comment = "Service的资源名") String name, @RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) { @RestParam(name = "type", comment = "Service的类名") String type) {
// 待开发 // 待开发
return RetResult.success(); return RetResult.success();
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -23,63 +23,63 @@ import org.redkale.service.LoadMode;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Cached { public @interface Cached {
/** /**
* 缓存的key支持参数动态组合比如"key_#{id}" * 缓存的key支持参数动态组合比如"key_#{id}"
* *
* @return 键 * @return 键
*/ */
String key(); String key();
/** /**
* 缓存的hash, 不能含有':'、'#'、'@'字符 * 缓存的hash, 不能含有':'、'#'、'@'字符
* *
* @return hash * @return hash
*/ */
String hash() default CacheManager.DEFAULT_HASH; String hash() default CacheManager.DEFAULT_HASH;
/** /**
* 本地缓存过期时长, 0表示永不过期 -1表示不作本地缓存。<br> * 本地缓存过期时长, 0表示永不过期 -1表示不作本地缓存。<br>
* 参数值支持方式:<br> * 参数值支持方式:<br>
* 100: 设置数值 ${env.cache.expires}: 读取系统配置项 * 100: 设置数值 ${env.cache.expires}: 读取系统配置项
* *
* @return 过期时长 * @return 过期时长
*/ */
String localExpire() default "-1"; String localExpire() default "-1";
/** /**
* 远程缓存过期时长, 0表示永不过期 -1表示不作远程缓存。<br> * 远程缓存过期时长, 0表示永不过期 -1表示不作远程缓存。<br>
* 参数值支持方式:<br> * 参数值支持方式:<br>
* 100: 设置数值 ${env.cache.expires}: 读取系统配置项 * 100: 设置数值 ${env.cache.expires}: 读取系统配置项
* *
* @return 过期时长 * @return 过期时长
*/ */
String remoteExpire() default "-1"; String remoteExpire() default "-1";
/** /**
* 是否可以缓存null值 * 是否可以缓存null值
* *
* @return 是否可以缓存null * @return 是否可以缓存null
*/ */
boolean nullable() default false; boolean nullable() default false;
/** /**
* 过期时长的时间单位 * 过期时长的时间单位
* *
* @return 时间单位 * @return 时间单位
*/ */
TimeUnit timeUnit() default TimeUnit.SECONDS; TimeUnit timeUnit() default TimeUnit.SECONDS;
/** /**
* 备注 * 备注
* *
* @return 备注 * @return 备注
*/ */
String comment() default ""; String comment() default "";
/** /**
* Service加载模式 * Service加载模式
* *
* @return 模式 * @return 模式
*/ */
LoadMode mode() default LoadMode.ANY; LoadMode mode() default LoadMode.ANY;
} }

View File

@@ -29,128 +29,128 @@ import org.redkale.util.TypeToken;
@ClassDepends @ClassDepends
public class CacheAction { public class CacheAction {
@Resource @Resource
private Environment environment; private Environment environment;
@Resource @Resource
private CacheManager manager; private CacheManager manager;
private final CacheEntry cached; private final CacheEntry cached;
// Supplier对象的类型 // Supplier对象的类型
private final Type resultType; private final Type resultType;
// 缓存方法是否异步 // 缓存方法是否异步
private final boolean async; private final boolean async;
// 是否可以缓存null // 是否可以缓存null
private final boolean nullable; private final boolean nullable;
// 宿主对象的类 // 宿主对象的类
private final Class serviceClass; private final Class serviceClass;
// 无法获取动态的Method只能存方法名 // 无法获取动态的Method只能存方法名
private final String methodName; private final String methodName;
// 获取动态的字段名 // 获取动态的字段名
private final String fieldName; private final String fieldName;
// 方法参数类型 // 方法参数类型
@Nullable @Nullable
private final Class[] paramTypes; private final Class[] paramTypes;
// 方法参数名 // 方法参数名
@Nullable @Nullable
private final String[] paramNames; private final String[] paramNames;
// 缓存的hash // 缓存的hash
private String hash; private String hash;
// 缓存的key // 缓存的key
private MultiHashKey dynKey; private MultiHashKey dynKey;
// 本地缓存过期时长Duration.ZERO为永不过期为null表示不本地缓存 // 本地缓存过期时长Duration.ZERO为永不过期为null表示不本地缓存
private Duration localExpire; private Duration localExpire;
// 远程缓存过期时长Duration.ZERO为永不过期为null表示不远程缓存 // 远程缓存过期时长Duration.ZERO为永不过期为null表示不远程缓存
private Duration remoteExpire; private Duration remoteExpire;
CacheAction( CacheAction(
CacheEntry cached, CacheEntry cached,
Type returnType, Type returnType,
Class serviceClass, Class serviceClass,
Class[] paramTypes, Class[] paramTypes,
String[] paramNames, String[] paramNames,
String methodName, String methodName,
String fieldName) { String fieldName) {
this.cached = cached; this.cached = cached;
this.nullable = cached.isNullable(); this.nullable = cached.isNullable();
this.serviceClass = Objects.requireNonNull(serviceClass); this.serviceClass = Objects.requireNonNull(serviceClass);
this.paramTypes = paramTypes; this.paramTypes = paramTypes;
this.paramNames = paramNames; this.paramNames = paramNames;
this.methodName = Objects.requireNonNull(methodName); this.methodName = Objects.requireNonNull(methodName);
this.fieldName = Objects.requireNonNull(fieldName); this.fieldName = Objects.requireNonNull(fieldName);
this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType)); this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType));
this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType; this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType;
} }
void init() { void init() {
this.hash = cached.getHash().trim().isEmpty() || CacheManager.DEFAULT_HASH.equals(cached.getHash()) this.hash = cached.getHash().trim().isEmpty() || CacheManager.DEFAULT_HASH.equals(cached.getHash())
? CacheManager.DEFAULT_HASH ? CacheManager.DEFAULT_HASH
: environment.getPropertyValue(cached.getHash()); : environment.getPropertyValue(cached.getHash());
String key = environment.getPropertyValue(cached.getKey()); String key = environment.getPropertyValue(cached.getKey());
this.dynKey = MultiHashKey.create(paramNames, key); this.dynKey = MultiHashKey.create(paramNames, key);
this.localExpire = createDuration(cached.getLocalExpire()); this.localExpire = createDuration(cached.getLocalExpire());
this.remoteExpire = createDuration(cached.getRemoteExpire()); this.remoteExpire = createDuration(cached.getRemoteExpire());
} }
@ClassDepends @ClassDepends
public <T> T get(ThrowSupplier<T> supplier, Object... args) { public <T> T get(ThrowSupplier<T> supplier, Object... args) {
if (async) { if (async) {
ThrowSupplier supplier0 = supplier; ThrowSupplier supplier0 = supplier;
return (T) manager.bothGetSetAsync( return (T) manager.bothGetSetAsync(
hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0); hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0);
} else { } else {
return manager.bothGetSet( return manager.bothGetSet(
hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier); hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier);
} }
} }
private Duration createDuration(String val) { private Duration createDuration(String val) {
String str = environment.getPropertyValue(val); String str = environment.getPropertyValue(val);
if ("-1".equals(str) || "null".equalsIgnoreCase(str)) { if ("-1".equals(str) || "null".equalsIgnoreCase(str)) {
return null; return null;
} else if ("0".equals(str)) { } else if ("0".equals(str)) {
return Duration.ZERO; return Duration.ZERO;
} else if (str.indexOf('*') > -1) { } else if (str.indexOf('*') > -1) {
long rs = 1; long rs = 1;
for (String v : str.split("\\*")) { for (String v : str.split("\\*")) {
if (!v.trim().isEmpty()) { if (!v.trim().isEmpty()) {
rs *= Long.parseLong(v.trim()); rs *= Long.parseLong(v.trim());
} }
} }
if (rs < 0) { if (rs < 0) {
return null; return null;
} else if (rs == 0) { } else if (rs == 0) {
return Duration.ZERO; return Duration.ZERO;
} else { } else {
return Duration.ofMillis(cached.getTimeUnit().toMillis(rs)); return Duration.ofMillis(cached.getTimeUnit().toMillis(rs));
} }
} else { } else {
return Duration.ofMillis(cached.getTimeUnit().toMillis(Long.parseLong(str))); return Duration.ofMillis(cached.getTimeUnit().toMillis(Long.parseLong(str)));
} }
} }
@Override @Override
public String toString() { public String toString() {
return "{" return "{"
+ "\"serviceClass\":" + serviceClass.getName() + "\"serviceClass\":" + serviceClass.getName()
+ ",\"methodName\":\"" + methodName + "\"" + ",\"methodName\":\"" + methodName + "\""
+ ",\"fieldName\":\"" + fieldName + "\"" + ",\"fieldName\":\"" + fieldName + "\""
+ ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes) + ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes)
+ ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames) + ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames)
+ ",\"resultType\":\"" + resultType + "\"" + ",\"resultType\":\"" + resultType + "\""
+ ",\"cache\":" + cached + ",\"cache\":" + cached
+ "}"; + "}";
} }
} }

View File

@@ -35,214 +35,214 @@ import org.redkale.util.TypeToken;
/** @author zhangjx */ /** @author zhangjx */
public class CacheAsmMethodBoost extends AsmMethodBoost { public class CacheAsmMethodBoost extends AsmMethodBoost {
private static final java.lang.reflect.Type FUTURE_VOID = new TypeToken<CompletableFuture<Void>>() {}.getType(); private static final java.lang.reflect.Type FUTURE_VOID = new TypeToken<CompletableFuture<Void>>() {}.getType();
private static final List<Class<? extends Annotation>> FILTER_ANN = List.of(Cached.class, DynForCache.class); private static final List<Class<? extends Annotation>> FILTER_ANN = List.of(Cached.class, DynForCache.class);
private Map<String, CacheAction> actionMap; private Map<String, CacheAction> actionMap;
public CacheAsmMethodBoost(boolean remote, Class serviceType) { public CacheAsmMethodBoost(boolean remote, Class serviceType) {
super(remote, serviceType); super(remote, serviceType);
} }
@Override @Override
public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) { public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) {
return FILTER_ANN; return FILTER_ANN;
} }
@Override @Override
public String doMethod( public String doMethod(
ClassLoader classLoader, ClassLoader classLoader,
ClassWriter cw, ClassWriter cw,
String newDynName, String newDynName,
String fieldPrefix, String fieldPrefix,
List filterAnns, List filterAnns,
Method method, Method method,
final String newMethodName) { final String newMethodName) {
Map<String, CacheAction> actions = this.actionMap; Map<String, CacheAction> actions = this.actionMap;
if (actions == null) { if (actions == null) {
actions = new LinkedHashMap<>(); actions = new LinkedHashMap<>();
this.actionMap = actions; this.actionMap = actions;
} }
Cached cached = method.getAnnotation(Cached.class); Cached cached = method.getAnnotation(Cached.class);
if (cached == null) { if (cached == null) {
return newMethodName; return newMethodName;
} }
if (!LoadMode.matches(remote, cached.mode())) { if (!LoadMode.matches(remote, cached.mode())) {
return newMethodName; return newMethodName;
} }
if (method.getAnnotation(DynForCache.class) != null) { if (method.getAnnotation(DynForCache.class) != null) {
return newMethodName; return newMethodName;
} }
if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
throw new RedkaleException( throw new RedkaleException(
"@" + Cached.class.getSimpleName() + " cannot on final or static method, but on " + method); "@" + Cached.class.getSimpleName() + " cannot on final or static method, but on " + method);
} }
if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) {
throw new RedkaleException( throw new RedkaleException(
"@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method); "@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method);
} }
if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) { if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) {
throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method); throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method);
} }
final int actionIndex = fieldIndex.incrementAndGet(); final int actionIndex = fieldIndex.incrementAndGet();
final String rsMethodName = method.getName() + "_afterCache"; final String rsMethodName = method.getName() + "_afterCache";
final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + actionIndex; final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + actionIndex;
final AsmMethodBean methodBean = getMethodBean(method); final AsmMethodBean methodBean = getMethodBean(method);
{ // 定义一个新方法调用 this.rsMethodName { // 定义一个新方法调用 this.rsMethodName
final String cacheDynDesc = Type.getDescriptor(DynForCache.class); final String cacheDynDesc = Type.getDescriptor(DynForCache.class);
final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean);
// mv.setDebug(true); // mv.setDebug(true);
AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true); AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true);
av.visit("dynField", dynFieldName); av.visit("dynField", dynFieldName);
Asms.visitAnnotation(av, cached); Asms.visitAnnotation(av, cached);
visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns); visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns);
Label l0 = new Label(); Label l0 = new Label();
mv.visitLabel(l0); mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
List<Integer> insns = visitVarInsnParamTypes(mv, method, 0); List<Integer> insns = visitVarInsnParamTypes(mv, method, 0);
String dynDesc = methodBean.getDesc(); String dynDesc = methodBean.getDesc();
dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1) dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1)
+ Type.getDescriptor(ThrowSupplier.class); + Type.getDescriptor(ThrowSupplier.class);
mv.visitInvokeDynamicInsn("get", dynDesc, Asms.createLambdaMetaHandle(), new Object[] { mv.visitInvokeDynamicInsn("get", dynDesc, Asms.createLambdaMetaHandle(), new Object[] {
org.redkale.asm.Type.getType("()Ljava/lang/Object;"), org.redkale.asm.Type.getType("()Ljava/lang/Object;"),
new Handle(Opcodes.H_INVOKESPECIAL, newDynName, "lambda$" + actionIndex, methodBean.getDesc(), false), new Handle(Opcodes.H_INVOKESPECIAL, newDynName, "lambda$" + actionIndex, methodBean.getDesc(), false),
org.redkale.asm.Type.getType("()" + Type.getDescriptor(method.getReturnType())) org.redkale.asm.Type.getType("()" + Type.getDescriptor(method.getReturnType()))
}); });
mv.visitVarInsn(ASTORE, 1 + method.getParameterCount()); mv.visitVarInsn(ASTORE, 1 + method.getParameterCount());
Label l1 = new Label(); Label l1 = new Label();
mv.visitLabel(l1); mv.visitLabel(l1);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, dynFieldName, Type.getDescriptor(CacheAction.class)); mv.visitFieldInsn(GETFIELD, newDynName, dynFieldName, Type.getDescriptor(CacheAction.class));
mv.visitVarInsn(ALOAD, 1 + method.getParameterCount()); mv.visitVarInsn(ALOAD, 1 + method.getParameterCount());
Asms.visitInsn(mv, method.getParameterCount()); Asms.visitInsn(mv, method.getParameterCount());
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int insn = 0; int insn = 0;
Class[] paramtypes = method.getParameterTypes(); Class[] paramtypes = method.getParameterTypes();
for (int j = 0; j < paramtypes.length; j++) { for (int j = 0; j < paramtypes.length; j++) {
final Class pt = paramtypes[j]; final Class pt = paramtypes[j];
mv.visitInsn(DUP); mv.visitInsn(DUP);
insn++; insn++;
Asms.visitInsn(mv, j); Asms.visitInsn(mv, j);
if (pt.isPrimitive()) { if (pt.isPrimitive()) {
if (pt == long.class) { if (pt == long.class) {
mv.visitVarInsn(LLOAD, insn++); mv.visitVarInsn(LLOAD, insn++);
} else if (pt == float.class) { } else if (pt == float.class) {
mv.visitVarInsn(FLOAD, insn++); mv.visitVarInsn(FLOAD, insn++);
} else if (pt == double.class) { } else if (pt == double.class) {
mv.visitVarInsn(DLOAD, insn++); mv.visitVarInsn(DLOAD, insn++);
} else { } else {
mv.visitVarInsn(ILOAD, insn); mv.visitVarInsn(ILOAD, insn);
} }
Class bigclaz = TypeToken.primitiveToWrapper(pt); Class bigclaz = TypeToken.primitiveToWrapper(pt);
mv.visitMethodInsn( mv.visitMethodInsn(
INVOKESTATIC, INVOKESTATIC,
bigclaz.getName().replace('.', '/'), bigclaz.getName().replace('.', '/'),
"valueOf", "valueOf",
"(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz),
false); false);
} else { } else {
mv.visitVarInsn(ALOAD, insn); mv.visitVarInsn(ALOAD, insn);
} }
mv.visitInsn(AASTORE); mv.visitInsn(AASTORE);
} }
String throwFuncDesc = Type.getDescriptor(ThrowSupplier.class); String throwFuncDesc = Type.getDescriptor(ThrowSupplier.class);
mv.visitMethodInsn( mv.visitMethodInsn(
INVOKEVIRTUAL, INVOKEVIRTUAL,
CacheAction.class.getName().replace('.', '/'), CacheAction.class.getName().replace('.', '/'),
"get", "get",
"(" + throwFuncDesc + "[Ljava/lang/Object;)Ljava/lang/Object;", "(" + throwFuncDesc + "[Ljava/lang/Object;)Ljava/lang/Object;",
false); false);
mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/')); mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/'));
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
Label l2 = new Label(); Label l2 = new Label();
mv.visitLabel(l2); mv.visitLabel(l2);
mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0); mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0);
visitParamTypesLocalVariable(mv, method, l0, l2, insns, methodBean); visitParamTypesLocalVariable(mv, method, l0, l2, insns, methodBean);
mv.visitLocalVariable("_redkale_supplier", Type.getDescriptor(ThrowSupplier.class), null, l1, l2, ++insn); mv.visitLocalVariable("_redkale_supplier", Type.getDescriptor(ThrowSupplier.class), null, l1, l2, ++insn);
mv.visitMaxs(20, 20); mv.visitMaxs(20, 20);
mv.visitEnd(); mv.visitEnd();
CacheAction action = new CacheAction( CacheAction action = new CacheAction(
new CacheEntry(cached), new CacheEntry(cached),
method.getGenericReturnType(), method.getGenericReturnType(),
serviceType, serviceType,
method.getParameterTypes(), method.getParameterTypes(),
methodBean.fieldNameArray(), methodBean.fieldNameArray(),
method.getName(), method.getName(),
dynFieldName); dynFieldName);
actions.put(dynFieldName, action); actions.put(dynFieldName, action);
} }
{ // ThrowSupplier { // ThrowSupplier
final MethodVisitor mv = cw.visitMethod( final MethodVisitor mv = cw.visitMethod(
ACC_PRIVATE + ACC_SYNTHETIC, "lambda$" + actionIndex, methodBean.getDesc(), null, new String[] { ACC_PRIVATE + ACC_SYNTHETIC, "lambda$" + actionIndex, methodBean.getDesc(), null, new String[] {
"java/lang/Throwable" "java/lang/Throwable"
}); });
// mv.setDebug(true); // mv.setDebug(true);
Label l0 = new Label(); Label l0 = new Label();
mv.visitLabel(l0); mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
visitVarInsnParamTypes(mv, method, 0); visitVarInsnParamTypes(mv, method, 0);
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, methodBean.getDesc(), false); mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, methodBean.getDesc(), false);
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
Label l1 = new Label(); Label l1 = new Label();
mv.visitLabel(l1); mv.visitLabel(l1);
mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l1, 0); mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l1, 0);
mv.visitMaxs(5, 5); mv.visitMaxs(5, 5);
mv.visitEnd(); mv.visitEnd();
} }
{ // 定义字段 { // 定义字段
FieldVisitor fv = FieldVisitor fv =
cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null); cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null);
fv.visitEnd(); fv.visitEnd();
} }
if (actions.size() == 1) { if (actions.size() == 1) {
cw.visitInnerClass( cw.visitInnerClass(
"java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles$Lookup",
"java/lang/invoke/MethodHandles", "java/lang/invoke/MethodHandles",
"Lookup", "Lookup",
ACC_PUBLIC + ACC_FINAL + ACC_STATIC); ACC_PUBLIC + ACC_FINAL + ACC_STATIC);
} }
return rsMethodName; return rsMethodName;
} }
@Override @Override
public void doInstance(ResourceFactory resourceFactory, Object service) { public void doInstance(ResourceFactory resourceFactory, Object service) {
Class clazz = service.getClass(); Class clazz = service.getClass();
if (actionMap == null) { // 为null表示没有调用过doMethod 动态类在编译是已经生成好了 if (actionMap == null) { // 为null表示没有调用过doMethod 动态类在编译是已经生成好了
actionMap = new LinkedHashMap<>(); actionMap = new LinkedHashMap<>();
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(clazz); Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(clazz);
for (final Method method : clazz.getDeclaredMethods()) { for (final Method method : clazz.getDeclaredMethods()) {
DynForCache cached = method.getAnnotation(DynForCache.class); DynForCache cached = method.getAnnotation(DynForCache.class);
if (cached != null) { if (cached != null) {
String dynFieldName = cached.dynField(); String dynFieldName = cached.dynField();
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
CacheAction action = new CacheAction( CacheAction action = new CacheAction(
new CacheEntry(cached), new CacheEntry(cached),
method.getGenericReturnType(), method.getGenericReturnType(),
serviceType, serviceType,
method.getParameterTypes(), method.getParameterTypes(),
methodBean.fieldNameArray(), methodBean.fieldNameArray(),
method.getName(), method.getName(),
dynFieldName); dynFieldName);
actionMap.put(dynFieldName, action); actionMap.put(dynFieldName, action);
} }
} }
} }
actionMap.forEach((field, action) -> { actionMap.forEach((field, action) -> {
try { try {
Field c = clazz.getDeclaredField(field); Field c = clazz.getDeclaredField(field);
c.setAccessible(true); c.setAccessible(true);
resourceFactory.inject(action); resourceFactory.inject(action);
action.init(); action.init();
c.set(service, action); c.set(service, action);
RedkaleClassLoader.putReflectionField(clazz.getName(), c); RedkaleClassLoader.putReflectionField(clazz.getName(), c);
} catch (Exception e) { } catch (Exception e) {
throw new RedkaleException("field (" + field + ") in " + clazz.getName() + " set error", e); throw new RedkaleException("field (" + field + ") in " + clazz.getName() + " set error", e);
} }
}); });
// do nothing // do nothing
} }
} }

View File

@@ -10,88 +10,88 @@ import org.redkale.convert.json.JsonConvert;
/** @author zhangjx */ /** @author zhangjx */
public class CacheEntry { public class CacheEntry {
private String key; private String key;
private String hash; private String hash;
private String localExpire; private String localExpire;
private String remoteExpire; private String remoteExpire;
private TimeUnit timeUnit; private TimeUnit timeUnit;
private boolean nullable; private boolean nullable;
public CacheEntry() {} public CacheEntry() {}
public CacheEntry(DynForCache cached) { public CacheEntry(DynForCache cached) {
this.key = cached.key(); this.key = cached.key();
this.hash = cached.hash(); this.hash = cached.hash();
this.localExpire = cached.localExpire(); this.localExpire = cached.localExpire();
this.remoteExpire = cached.remoteExpire(); this.remoteExpire = cached.remoteExpire();
this.timeUnit = cached.timeUnit(); this.timeUnit = cached.timeUnit();
this.nullable = cached.nullable(); this.nullable = cached.nullable();
} }
public CacheEntry(Cached cached) { public CacheEntry(Cached cached) {
this.key = cached.key(); this.key = cached.key();
this.hash = cached.hash(); this.hash = cached.hash();
this.localExpire = cached.localExpire(); this.localExpire = cached.localExpire();
this.remoteExpire = cached.remoteExpire(); this.remoteExpire = cached.remoteExpire();
this.timeUnit = cached.timeUnit(); this.timeUnit = cached.timeUnit();
this.nullable = cached.nullable(); this.nullable = cached.nullable();
} }
public String getKey() { public String getKey() {
return key; return key;
} }
public void setKey(String key) { public void setKey(String key) {
this.key = key; this.key = key;
} }
public String getHash() { public String getHash() {
return hash; return hash;
} }
public void setHash(String hash) { public void setHash(String hash) {
this.hash = hash; this.hash = hash;
} }
public String getLocalExpire() { public String getLocalExpire() {
return localExpire; return localExpire;
} }
public void setLocalExpire(String localExpire) { public void setLocalExpire(String localExpire) {
this.localExpire = localExpire; this.localExpire = localExpire;
} }
public String getRemoteExpire() { public String getRemoteExpire() {
return remoteExpire; return remoteExpire;
} }
public void setRemoteExpire(String remoteExpire) { public void setRemoteExpire(String remoteExpire) {
this.remoteExpire = remoteExpire; this.remoteExpire = remoteExpire;
} }
public TimeUnit getTimeUnit() { public TimeUnit getTimeUnit() {
return timeUnit; return timeUnit;
} }
public void setTimeUnit(TimeUnit timeUnit) { public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit; this.timeUnit = timeUnit;
} }
public boolean isNullable() { public boolean isNullable() {
return nullable; return nullable;
} }
public void setNullable(boolean nullable) { public void setNullable(boolean nullable) {
this.nullable = nullable; this.nullable = nullable;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -19,83 +19,83 @@ import org.redkale.util.RedkaleClassLoader;
/** @author zhangjx */ /** @author zhangjx */
public class CacheModuleEngine extends ModuleEngine { public class CacheModuleEngine extends ModuleEngine {
// 全局缓存管理器 // 全局缓存管理器
private CacheManager cacheManager; private CacheManager cacheManager;
private AnyValue config; private AnyValue config;
public CacheModuleEngine(Application application) { public CacheModuleEngine(Application application) {
super(application); super(application);
} }
/** /**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
* *
* @param path 配置项路径 * @param path 配置项路径
* @param key 配置项名称 * @param key 配置项名称
* @param val1 配置项原值 * @param val1 配置项原值
* @param val2 配置项新值 * @param val2 配置项新值
* @return MergeEnum * @return MergeEnum
*/ */
@Override @Override
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
if ("".equals(path) && "cache".equals(key)) { if ("".equals(path) && "cache".equals(key)) {
return AnyValue.MergeEnum.REPLACE; return AnyValue.MergeEnum.REPLACE;
} }
return null; return null;
} }
/** /**
* 动态扩展类的方法 * 动态扩展类的方法
* *
* @param remote 是否远程模式 * @param remote 是否远程模式
* @param serviceClass 类 * @param serviceClass 类
* @return 方法动态扩展器 * @return 方法动态扩展器
*/ */
@Override @Override
public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) { public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) {
return new CacheAsmMethodBoost(remote, serviceClass); return new CacheAsmMethodBoost(remote, serviceClass);
} }
/** 结束Application.init方法前被调用 */ /** 结束Application.init方法前被调用 */
@Override @Override
public void onAppPostInit() { public void onAppPostInit() {
// 设置缓存管理器 // 设置缓存管理器
this.config = application.getAppConfig().getAnyValue("cache"); this.config = application.getAppConfig().getAnyValue("cache");
this.cacheManager = createManager(this.config); this.cacheManager = createManager(this.config);
if (!application.isCompileMode()) { if (!application.isCompileMode()) {
this.resourceFactory.inject(this.cacheManager); this.resourceFactory.inject(this.cacheManager);
if (this.cacheManager instanceof Service) { if (this.cacheManager instanceof Service) {
((Service) this.cacheManager).init(this.config); ((Service) this.cacheManager).init(this.config);
} }
} }
this.resourceFactory.register("", CacheManager.class, this.cacheManager); this.resourceFactory.register("", CacheManager.class, this.cacheManager);
} }
/** 进入Application.shutdown方法被调用 */ /** 进入Application.shutdown方法被调用 */
@Override @Override
public void onAppPreShutdown() { public void onAppPreShutdown() {
if (!application.isCompileMode() && this.cacheManager instanceof Service) { if (!application.isCompileMode() && this.cacheManager instanceof Service) {
((Service) this.cacheManager).destroy(this.config); ((Service) this.cacheManager).destroy(this.config);
} }
} }
private CacheManager createManager(AnyValue conf) { private CacheManager createManager(AnyValue conf) {
Iterator<CacheManagerProvider> it = ServiceLoader.load(CacheManagerProvider.class, application.getClassLoader()) Iterator<CacheManagerProvider> it = ServiceLoader.load(CacheManagerProvider.class, application.getClassLoader())
.iterator(); .iterator();
RedkaleClassLoader.putServiceLoader(CacheManagerProvider.class); RedkaleClassLoader.putServiceLoader(CacheManagerProvider.class);
List<CacheManagerProvider> providers = new ArrayList<>(); List<CacheManagerProvider> providers = new ArrayList<>();
while (it.hasNext()) { while (it.hasNext()) {
CacheManagerProvider provider = it.next(); CacheManagerProvider provider = it.next();
if (provider != null && provider.acceptsConf(conf)) { if (provider != null && provider.acceptsConf(conf)) {
RedkaleClassLoader.putReflectionPublicConstructors( RedkaleClassLoader.putReflectionPublicConstructors(
provider.getClass(), provider.getClass().getName()); provider.getClass(), provider.getClass().getName());
providers.add(provider); providers.add(provider);
} }
} }
for (CacheManagerProvider provider : InstanceProvider.sort(providers)) { for (CacheManagerProvider provider : InstanceProvider.sort(providers)) {
return provider.createInstance(); return provider.createInstance();
} }
return CacheManagerService.create(null).enabled(false); return CacheManagerService.create(null).enabled(false);
} }
} }

View File

@@ -17,37 +17,37 @@ import org.redkale.convert.json.JsonConvert;
*/ */
public class CacheValue<T> { public class CacheValue<T> {
@ConvertColumn(index = 1) @ConvertColumn(index = 1)
private T val; private T val;
public CacheValue() {} public CacheValue() {}
protected CacheValue(T value) { protected CacheValue(T value) {
this.val = value; this.val = value;
} }
public static <T> CacheValue<T> create(T value) { public static <T> CacheValue<T> create(T value) {
return new CacheValue(value); return new CacheValue(value);
} }
public static boolean isValid(CacheValue val) { public static boolean isValid(CacheValue val) {
return val != null; return val != null;
} }
public static <T> T get(CacheValue val) { public static <T> T get(CacheValue val) {
return isValid(val) ? (T) val.getVal() : null; return isValid(val) ? (T) val.getVal() : null;
} }
public T getVal() { public T getVal() {
return val; return val;
} }
public void setVal(T val) { public void setVal(T val) {
this.val = val; this.val = val;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }

View File

@@ -23,19 +23,19 @@ import org.redkale.service.LoadMode;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface DynForCache { public @interface DynForCache {
String dynField(); String dynField();
String key(); String key();
String hash(); String hash();
String localExpire(); String localExpire();
String remoteExpire(); String remoteExpire();
TimeUnit timeUnit(); TimeUnit timeUnit();
boolean nullable(); boolean nullable();
LoadMode mode() default LoadMode.ANY; LoadMode mode() default LoadMode.ANY;
} }

View File

@@ -17,19 +17,19 @@ import java.util.concurrent.CompletableFuture;
*/ */
public interface ClusterRpcClient<R, P> { public interface ClusterRpcClient<R, P> {
/** /**
* 发送消息,需要响应 * 发送消息,需要响应
* *
* @param message 消息体 * @param message 消息体
* @return 应答消息 * @return 应答消息
*/ */
public CompletableFuture<P> sendMessage(final R message); public CompletableFuture<P> sendMessage(final R message);
/** /**
* 发送消息,无需响应 * 发送消息,无需响应
* *
* @param message 消息体 * @param message 消息体
* @return 应答 * @return 应答
*/ */
public CompletableFuture<Void> produceMessage(R message); public CompletableFuture<Void> produceMessage(R message);
} }

View File

@@ -22,106 +22,106 @@ import org.redkale.util.RedkaleException;
*/ */
public abstract class HttpRpcClient implements ClusterRpcClient<WebRequest, HttpResult<byte[]>> { public abstract class HttpRpcClient implements ClusterRpcClient<WebRequest, HttpResult<byte[]>> {
@Override @Override
public final CompletableFuture<Void> produceMessage(WebRequest request) { public final CompletableFuture<Void> produceMessage(WebRequest request) {
return produceMessage(generateHttpReqTopic(request, null), 0, null, request); return produceMessage(generateHttpReqTopic(request, null), 0, null, request);
} }
public final CompletableFuture<Void> produceMessage(Serializable userid, WebRequest request) { public final CompletableFuture<Void> produceMessage(Serializable userid, WebRequest request) {
return produceMessage(generateHttpReqTopic(request, null), userid, null, request); return produceMessage(generateHttpReqTopic(request, null), userid, null, request);
} }
public final CompletableFuture<Void> produceMessage(Serializable userid, String groupid, WebRequest request) { public final CompletableFuture<Void> produceMessage(Serializable userid, String groupid, WebRequest request) {
return produceMessage(generateHttpReqTopic(request, null), userid, groupid, request); return produceMessage(generateHttpReqTopic(request, null), userid, groupid, request);
} }
public final CompletableFuture<Void> produceMessage(String topic, WebRequest request) { public final CompletableFuture<Void> produceMessage(String topic, WebRequest request) {
return produceMessage(topic, 0, null, request); return produceMessage(topic, 0, null, request);
} }
@Override @Override
public final CompletableFuture<HttpResult<byte[]>> sendMessage(WebRequest request) { public final CompletableFuture<HttpResult<byte[]>> sendMessage(WebRequest request) {
return sendMessage(generateHttpReqTopic(request, null), 0, null, request); return sendMessage(generateHttpReqTopic(request, null), 0, null, request);
} }
public final CompletableFuture<HttpResult<byte[]>> sendMessage(Serializable userid, WebRequest request) { public final CompletableFuture<HttpResult<byte[]>> sendMessage(Serializable userid, WebRequest request) {
return sendMessage(generateHttpReqTopic(request, null), userid, null, request); return sendMessage(generateHttpReqTopic(request, null), userid, null, request);
} }
public final CompletableFuture<HttpResult<byte[]>> sendMessage( public final CompletableFuture<HttpResult<byte[]>> sendMessage(
Serializable userid, String groupid, WebRequest request) { Serializable userid, String groupid, WebRequest request) {
return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request); return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request);
} }
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, WebRequest request) { public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, WebRequest request) {
return sendMessage(topic, 0, null, request); return sendMessage(topic, 0, null, request);
} }
public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) { public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) {
return sendMessage(generateHttpReqTopic(request, null), 0, null, request) return sendMessage(generateHttpReqTopic(request, null), 0, null, request)
.thenApply((HttpResult<byte[]> httbs) -> { .thenApply((HttpResult<byte[]> httbs) -> {
if (!httbs.isSuccess()) { if (!httbs.isSuccess()) {
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error")); throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
} }
if (httbs.getResult() == null) { if (httbs.getResult() == null) {
return null; return null;
} }
return JsonConvert.root().convertFrom(type, httbs.getResult()); return JsonConvert.root().convertFrom(type, httbs.getResult());
}); });
} }
public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) { public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) {
return sendMessage(generateHttpReqTopic(request, null), userid, null, request) return sendMessage(generateHttpReqTopic(request, null), userid, null, request)
.thenApply((HttpResult<byte[]> httbs) -> { .thenApply((HttpResult<byte[]> httbs) -> {
if (!httbs.isSuccess()) { if (!httbs.isSuccess()) {
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error")); throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
} }
if (httbs.getResult() == null) { if (httbs.getResult() == null) {
return null; return null;
} }
return JsonConvert.root().convertFrom(type, httbs.getResult()); return JsonConvert.root().convertFrom(type, httbs.getResult());
}); });
} }
public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) { public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) {
return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request) return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request)
.thenApply((HttpResult<byte[]> httbs) -> { .thenApply((HttpResult<byte[]> httbs) -> {
if (!httbs.isSuccess()) { if (!httbs.isSuccess()) {
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error")); throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
} }
if (httbs.getResult() == null) { if (httbs.getResult() == null) {
return null; return null;
} }
return JsonConvert.root().convertFrom(type, httbs.getResult()); return JsonConvert.root().convertFrom(type, httbs.getResult());
}); });
} }
// 格式: http.req.user // 格式: http.req.user
public String generateHttpReqTopic(String module) { public String generateHttpReqTopic(String module) {
return Rest.generateHttpReqTopic(module, getNodeid()); return Rest.generateHttpReqTopic(module, getNodeid());
} }
// 格式: http.req.user-n10 // 格式: http.req.user-n10
public String generateHttpReqTopic(String module, String resname) { public String generateHttpReqTopic(String module, String resname) {
return Rest.generateHttpReqTopic(module, resname, getNodeid()); return Rest.generateHttpReqTopic(module, resname, getNodeid());
} }
public String generateHttpReqTopic(WebRequest request, String path) { public String generateHttpReqTopic(WebRequest request, String path) {
String module = request.getPath(); String module = request.getPath();
if (path != null && !path.isEmpty() && module.startsWith(path)) { if (path != null && !path.isEmpty() && module.startsWith(path)) {
module = module.substring(path.length()); module = module.substring(path.length());
} }
module = module.substring(1); // 去掉/ module = module.substring(1); // 去掉/
module = module.substring(0, module.indexOf('/')); module = module.substring(0, module.indexOf('/'));
String resname = request.getHeader(Rest.REST_HEADER_RESNAME, ""); String resname = request.getHeader(Rest.REST_HEADER_RESNAME, "");
return Rest.generateHttpReqTopic(module, resname, getNodeid()); return Rest.generateHttpReqTopic(module, resname, getNodeid());
} }
public abstract CompletableFuture<HttpResult<byte[]>> sendMessage( public abstract CompletableFuture<HttpResult<byte[]>> sendMessage(
String topic, Serializable userid, String groupid, WebRequest request); String topic, Serializable userid, String groupid, WebRequest request);
public abstract CompletableFuture<Void> produceMessage( public abstract CompletableFuture<Void> produceMessage(
String topic, Serializable userid, String groupid, WebRequest request); String topic, Serializable userid, String groupid, WebRequest request);
protected abstract String getNodeid(); protected abstract String getNodeid();
} }

View File

@@ -29,376 +29,376 @@ import org.redkale.util.*;
*/ */
public class CacheClusterAgent extends ClusterAgent implements Resourcable { public class CacheClusterAgent extends ClusterAgent implements Resourcable {
@Resource(name = Resource.PARENT_NAME) @Resource(name = Resource.PARENT_NAME)
private CacheSource source; private CacheSource source;
private String sourceName; private String sourceName;
protected int ttls = 10; // 定时检查的秒数 protected int ttls = 10; // 定时检查的秒数
protected ScheduledThreadPoolExecutor scheduler; protected ScheduledThreadPoolExecutor scheduler;
protected ScheduledFuture taskFuture; protected ScheduledFuture taskFuture;
// 可能被HttpMessageClient用到的服务 key: serviceName例如: cluster.service.http.user // 可能被HttpMessageClient用到的服务 key: serviceName例如: cluster.service.http.user
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, Set<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
// 可能被sncp用到的服务 key: serviceName, 例如: cluster.service.sncp.user // 可能被sncp用到的服务 key: serviceName, 例如: cluster.service.sncp.user
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> sncpAddressMap = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, Set<InetSocketAddress>> sncpAddressMap = new ConcurrentHashMap<>();
@Override @Override
public void init(AnyValue config) { public void init(AnyValue config) {
super.init(config); super.init(config);
this.sourceName = getSourceName(); this.sourceName = getSourceName();
this.ttls = config.getIntValue("ttls", 10); this.ttls = config.getIntValue("ttls", 10);
if (this.ttls < 5) { // 值不能太小 if (this.ttls < 5) { // 值不能太小
this.ttls = 10; this.ttls = 10;
} }
} }
@Override @Override
@ResourceChanged @ResourceChanged
public void onResourceChange(ResourceEvent[] events) { public void onResourceChange(ResourceEvent[] events) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int newTtls = this.ttls; int newTtls = this.ttls;
for (ResourceEvent event : events) { for (ResourceEvent event : events) {
if ("ttls".equals(event.name())) { if ("ttls".equals(event.name())) {
newTtls = Integer.parseInt(event.newValue().toString()); newTtls = Integer.parseInt(event.newValue().toString());
if (newTtls < 5) { if (newTtls < 5) {
sb.append(CacheClusterAgent.class.getSimpleName()) sb.append(CacheClusterAgent.class.getSimpleName())
.append("(name=") .append("(name=")
.append(resourceName()) .append(resourceName())
.append(") cannot change '") .append(") cannot change '")
.append(event.name()) .append(event.name())
.append("' to '") .append("' to '")
.append(event.coverNewValue()) .append(event.coverNewValue())
.append("'\r\n"); .append("'\r\n");
} else { } else {
sb.append(CacheClusterAgent.class.getSimpleName()) sb.append(CacheClusterAgent.class.getSimpleName())
.append("(name=") .append("(name=")
.append(resourceName()) .append(resourceName())
.append(") change '") .append(") change '")
.append(event.name()) .append(event.name())
.append("' to '") .append("' to '")
.append(event.coverNewValue()) .append(event.coverNewValue())
.append("'\r\n"); .append("'\r\n");
} }
} else { } else {
sb.append(CacheClusterAgent.class.getSimpleName()) sb.append(CacheClusterAgent.class.getSimpleName())
.append("(name=") .append("(name=")
.append(resourceName()) .append(resourceName())
.append(") skip change '") .append(") skip change '")
.append(event.name()) .append(event.name())
.append("' to '") .append("' to '")
.append(event.coverNewValue()) .append(event.coverNewValue())
.append("'\r\n"); .append("'\r\n");
} }
} }
if (newTtls != this.ttls) { if (newTtls != this.ttls) {
this.ttls = newTtls; this.ttls = newTtls;
start(); start();
} }
if (sb.length() > 0) { if (sb.length() > 0) {
logger.log(Level.INFO, sb.toString()); logger.log(Level.INFO, sb.toString());
} }
} }
@Override @Override
public void setConfig(AnyValue config) { public void setConfig(AnyValue config) {
super.setConfig(config); super.setConfig(config);
this.sourceName = getSourceName(); this.sourceName = getSourceName();
} }
@Override @Override
public void destroy(AnyValue config) { public void destroy(AnyValue config) {
if (scheduler != null) { if (scheduler != null) {
scheduler.shutdownNow(); scheduler.shutdownNow();
} }
} }
public String getSourceName() { public String getSourceName() {
return config.getValue("source"); return config.getValue("source");
} }
@Override @Override
public String resourceName() { public String resourceName() {
return sourceName; return sourceName;
} }
@Override // ServiceLoader时判断配置是否符合当前实现类 @Override // ServiceLoader时判断配置是否符合当前实现类
public boolean acceptsConf(AnyValue config) { public boolean acceptsConf(AnyValue config) {
if (config == null) { if (config == null) {
return false; return false;
} }
return config.getValue("source") != null; return config.getValue("source") != null;
} }
@Override @Override
public void start() { public void start() {
if (this.scheduler == null) { if (this.scheduler == null) {
this.scheduler = Utility.newScheduledExecutor( this.scheduler = Utility.newScheduledExecutor(
1, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Check-Thread-%s"); 1, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Check-Thread-%s");
} }
if (this.taskFuture != null) { if (this.taskFuture != null) {
this.taskFuture.cancel(true); this.taskFuture.cancel(true);
} }
this.taskFuture = this.scheduler.scheduleAtFixedRate(newTask(), ttls, ttls, TimeUnit.SECONDS); this.taskFuture = this.scheduler.scheduleAtFixedRate(newTask(), ttls, ttls, TimeUnit.SECONDS);
} }
private Runnable newTask() { private Runnable newTask() {
return () -> { return () -> {
try { try {
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
localEntrys.values().stream().filter(e -> !e.canceled).forEach(this::checkLocalHealth); localEntrys.values().stream().filter(e -> !e.canceled).forEach(this::checkLocalHealth);
remoteEntrys.values().stream() remoteEntrys.values().stream()
.filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)) .filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol))
.forEach(this::updateSncpAddress); .forEach(this::updateSncpAddress);
checkApplicationHealth(); checkApplicationHealth();
checkHttpAddressHealth(); checkHttpAddressHealth();
loadSncpAddressHealth(); loadSncpAddressHealth();
long e = System.currentTimeMillis() - s; long e = System.currentTimeMillis() - s;
if (e >= ttls * 9 / 10) { if (e >= ttls * 9 / 10) {
logger.log(Level.WARNING, getClass().getSimpleName() + ".schedule check-slower cost " + e + " ms"); logger.log(Level.WARNING, getClass().getSimpleName() + ".schedule check-slower cost " + e + " ms");
} else if (e >= ttls / 2) { } else if (e >= ttls / 2) {
logger.log(Level.FINE, getClass().getSimpleName() + ".schedule check-slowly cost " + e + " ms"); logger.log(Level.FINE, getClass().getSimpleName() + ".schedule check-slowly cost " + e + " ms");
} else { } else {
logger.log(Level.FINEST, getClass().getSimpleName() + ".schedule check cost " + e + " ms"); logger.log(Level.FINEST, getClass().getSimpleName() + ".schedule check cost " + e + " ms");
} }
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, getClass().getSimpleName() + ".schedule check error", e); logger.log(Level.SEVERE, getClass().getSimpleName() + ".schedule check error", e);
} }
}; };
} }
protected void loadSncpAddressHealth() { protected void loadSncpAddressHealth() {
List<String> keys = source.keysStartsWith("cluster.sncp:"); List<String> keys = source.keysStartsWith("cluster.sncp:");
keys.forEach(serviceName -> { keys.forEach(serviceName -> {
try { try {
this.sncpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS)); this.sncpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "loadSncpAddressHealth check " + serviceName + " error", e); logger.log(Level.SEVERE, "loadSncpAddressHealth check " + serviceName + " error", e);
} }
}); });
} }
protected void checkHttpAddressHealth() { protected void checkHttpAddressHealth() {
try { try {
this.httpAddressMap.keySet().stream().forEach(serviceName -> { this.httpAddressMap.keySet().stream().forEach(serviceName -> {
try { try {
this.httpAddressMap.put( this.httpAddressMap.put(
serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS)); serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + serviceName + " error", e); logger.log(Level.SEVERE, "checkHttpAddressHealth check " + serviceName + " error", e);
} }
}); });
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex); logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex);
} }
} }
protected void checkLocalHealth(final ClusterEntry entry) { protected void checkLocalHealth(final ClusterEntry entry) {
AddressEntry newaddr = new AddressEntry(); AddressEntry newaddr = new AddressEntry();
newaddr.addr = entry.address; newaddr.addr = entry.address;
newaddr.resname = entry.resourceName; newaddr.resname = entry.resourceName;
newaddr.nodeid = this.nodeid; newaddr.nodeid = this.nodeid;
newaddr.time = System.currentTimeMillis(); newaddr.time = System.currentTimeMillis();
source.hset(entry.checkName, entry.checkid, AddressEntry.class, newaddr); source.hset(entry.checkName, entry.checkid, AddressEntry.class, newaddr);
} }
@Override // 获取SNCP远程服务的可用ip列表 @Override // 获取SNCP远程服务的可用ip列表
public CompletableFuture<Set<InetSocketAddress>> querySncpAddress(String protocol, String module, String resname) { public CompletableFuture<Set<InetSocketAddress>> querySncpAddress(String protocol, String module, String resname) {
final String serviceName = generateSncpServiceName(protocol, module, resname); final String serviceName = generateSncpServiceName(protocol, module, resname);
Set<InetSocketAddress> rs = sncpAddressMap.get(serviceName); Set<InetSocketAddress> rs = sncpAddressMap.get(serviceName);
if (rs != null) { if (rs != null) {
return CompletableFuture.completedFuture(rs); return CompletableFuture.completedFuture(rs);
} }
return queryAddress(serviceName).thenApply(t -> { return queryAddress(serviceName).thenApply(t -> {
sncpAddressMap.put(serviceName, t); sncpAddressMap.put(serviceName, t);
return t; return t;
}); });
} }
@Override // 获取HTTP远程服务的可用ip列表 @Override // 获取HTTP远程服务的可用ip列表
public CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) { public CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
final String serviceName = generateHttpServiceName(protocol, module, resname); final String serviceName = generateHttpServiceName(protocol, module, resname);
Set<InetSocketAddress> rs = httpAddressMap.get(serviceName); Set<InetSocketAddress> rs = httpAddressMap.get(serviceName);
if (rs != null) { if (rs != null) {
return CompletableFuture.completedFuture(rs); return CompletableFuture.completedFuture(rs);
} }
return queryAddress(serviceName).thenApply(t -> { return queryAddress(serviceName).thenApply(t -> {
httpAddressMap.put(serviceName, t); httpAddressMap.put(serviceName, t);
return t; return t;
}); });
} }
@Override @Override
protected CompletableFuture<Set<InetSocketAddress>> queryAddress(final ClusterEntry entry) { protected CompletableFuture<Set<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
return queryAddress(entry.serviceName); return queryAddress(entry.serviceName);
} }
private CompletableFuture<Set<InetSocketAddress>> queryAddress(final String serviceName) { private CompletableFuture<Set<InetSocketAddress>> queryAddress(final String serviceName) {
return queryAddress0(serviceName, new HashSet<>(), new AtomicLong()); return queryAddress0(serviceName, new HashSet<>(), new AtomicLong());
} }
private CompletableFuture<Set<InetSocketAddress>> queryAddress0( private CompletableFuture<Set<InetSocketAddress>> queryAddress0(
String serviceName, Set<InetSocketAddress> set, AtomicLong cursor) { String serviceName, Set<InetSocketAddress> set, AtomicLong cursor) {
final CompletableFuture<Map<String, AddressEntry>> future = final CompletableFuture<Map<String, AddressEntry>> future =
source.hscanAsync(serviceName, AddressEntry.class, cursor, 10000); source.hscanAsync(serviceName, AddressEntry.class, cursor, 10000);
return future.thenCompose(map -> { return future.thenCompose(map -> {
map.forEach((n, v) -> { map.forEach((n, v) -> {
if (v != null && (System.currentTimeMillis() - v.time) / 1000 <= ttls) { if (v != null && (System.currentTimeMillis() - v.time) / 1000 <= ttls) {
set.add(v.addr); set.add(v.addr);
} }
}); });
if (cursor.get() == 0) { if (cursor.get() == 0) {
return CompletableFuture.completedFuture(set); return CompletableFuture.completedFuture(set);
} else { } else {
return queryAddress0(serviceName, set, cursor); return queryAddress0(serviceName, set, cursor);
} }
}); });
} }
protected boolean isApplicationHealth() { protected boolean isApplicationHealth() {
String serviceName = generateApplicationServiceName(); String serviceName = generateApplicationServiceName();
String serviceid = generateApplicationServiceId(); String serviceid = generateApplicationServiceId();
AddressEntry entry = (AddressEntry) source.hget(serviceName, serviceid, AddressEntry.class); AddressEntry entry = (AddressEntry) source.hget(serviceName, serviceid, AddressEntry.class);
return entry != null && (System.currentTimeMillis() - entry.time) / 1000 <= ttls; return entry != null && (System.currentTimeMillis() - entry.time) / 1000 <= ttls;
} }
protected void checkApplicationHealth() { protected void checkApplicationHealth() {
String checkName = generateApplicationServiceName(); String checkName = generateApplicationServiceName();
String checkid = generateApplicationCheckId(); String checkid = generateApplicationCheckId();
AddressEntry entry = new AddressEntry(); AddressEntry entry = new AddressEntry();
entry.addr = this.appAddress; entry.addr = this.appAddress;
entry.nodeid = this.nodeid; entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis(); entry.time = System.currentTimeMillis();
source.hset(checkName, checkid, AddressEntry.class, entry); source.hset(checkName, checkid, AddressEntry.class, entry);
} }
@Override @Override
public void register(Application application) { public void register(Application application) {
if (isApplicationHealth()) { if (isApplicationHealth()) {
throw new RedkaleException("application.nodeid=" + nodeid + " exists in cluster"); throw new RedkaleException("application.nodeid=" + nodeid + " exists in cluster");
} }
deregister(application); deregister(application);
String serviceid = generateApplicationServiceId(); String serviceid = generateApplicationServiceId();
String serviceName = generateApplicationServiceName(); String serviceName = generateApplicationServiceName();
AddressEntry entry = new AddressEntry(); AddressEntry entry = new AddressEntry();
entry.addr = this.appAddress; entry.addr = this.appAddress;
entry.nodeid = this.nodeid; entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis(); entry.time = System.currentTimeMillis();
source.hset(serviceName, serviceid, AddressEntry.class, entry); source.hset(serviceName, serviceid, AddressEntry.class, entry);
} }
@Override @Override
public void deregister(Application application) { public void deregister(Application application) {
String serviceid = generateApplicationServiceId(); String serviceid = generateApplicationServiceId();
String serviceName = generateApplicationServiceName(); String serviceName = generateApplicationServiceName();
source.hdel(serviceName, serviceid); source.hdel(serviceName, serviceid);
} }
@Override @Override
protected ClusterEntry register(NodeServer ns, String protocol, Service service) { protected ClusterEntry register(NodeServer ns, String protocol, Service service) {
deregister(ns, protocol, service, false); deregister(ns, protocol, service, false);
// //
ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service); ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service);
AddressEntry entry = new AddressEntry(); AddressEntry entry = new AddressEntry();
entry.addr = clusterEntry.address; entry.addr = clusterEntry.address;
entry.resname = clusterEntry.resourceName; entry.resname = clusterEntry.resourceName;
entry.nodeid = this.nodeid; entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis(); entry.time = System.currentTimeMillis();
source.hset(clusterEntry.serviceName, clusterEntry.serviceid, AddressEntry.class, entry); source.hset(clusterEntry.serviceName, clusterEntry.serviceid, AddressEntry.class, entry);
return clusterEntry; return clusterEntry;
} }
@Override @Override
protected void deregister(NodeServer ns, String protocol, Service service) { protected void deregister(NodeServer ns, String protocol, Service service) {
deregister(ns, protocol, service, true); deregister(ns, protocol, service, true);
} }
protected void deregister(NodeServer ns, String protocol, Service service, boolean realCanceled) { protected void deregister(NodeServer ns, String protocol, Service service, boolean realCanceled) {
String serviceName = generateServiceName(ns, protocol, service); String serviceName = generateServiceName(ns, protocol, service);
String serviceid = generateServiceId(ns, protocol, service); String serviceid = generateServiceId(ns, protocol, service);
ClusterEntry currEntry = null; ClusterEntry currEntry = null;
for (final ClusterEntry entry : localEntrys.values()) { for (final ClusterEntry entry : localEntrys.values()) {
if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) { if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) {
currEntry = entry; currEntry = entry;
break; break;
} }
} }
if (currEntry == null) { if (currEntry == null) {
for (final ClusterEntry entry : remoteEntrys.values()) { for (final ClusterEntry entry : remoteEntrys.values()) {
if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) { if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) {
currEntry = entry; currEntry = entry;
break; break;
} }
} }
} }
source.hdel(serviceName, serviceid); source.hdel(serviceName, serviceid);
if (realCanceled && currEntry != null) { if (realCanceled && currEntry != null) {
currEntry.canceled = true; currEntry.canceled = true;
} }
} }
@Override @Override
protected String generateApplicationServiceName() { protected String generateApplicationServiceName() {
return "cluster:app:" + super.generateApplicationServiceName(); return "cluster:app:" + super.generateApplicationServiceName();
} }
@Override @Override
protected String generateServiceName(NodeServer ns, String protocol, Service service) { protected String generateServiceName(NodeServer ns, String protocol, Service service) {
return "cluster:service:" + super.generateServiceName(ns, protocol, service); return "cluster:service:" + super.generateServiceName(ns, protocol, service);
} }
@Override @Override
public String generateHttpServiceName(String protocol, String module, String resname) { public String generateHttpServiceName(String protocol, String module, String resname) {
return "cluster:service:" + super.generateHttpServiceName(protocol, module, resname); return "cluster:service:" + super.generateHttpServiceName(protocol, module, resname);
} }
@Override @Override
public String generateSncpServiceName(String protocol, String restype, String resname) { public String generateSncpServiceName(String protocol, String restype, String resname) {
return "cluster:service:" + super.generateSncpServiceName(protocol, restype, resname); return "cluster:service:" + super.generateSncpServiceName(protocol, restype, resname);
} }
@Override @Override
protected String generateApplicationCheckName() { protected String generateApplicationCheckName() {
return generateApplicationServiceName(); return generateApplicationServiceName();
} }
@Override @Override
protected String generateApplicationCheckId() { protected String generateApplicationCheckId() {
return generateApplicationServiceId(); return generateApplicationServiceId();
} }
@Override @Override
protected String generateCheckName(NodeServer ns, String protocol, Service service) { protected String generateCheckName(NodeServer ns, String protocol, Service service) {
return generateServiceName(ns, protocol, service); return generateServiceName(ns, protocol, service);
} }
@Override @Override
protected String generateCheckId(NodeServer ns, String protocol, Service service) { protected String generateCheckId(NodeServer ns, String protocol, Service service) {
return generateServiceId(ns, protocol, service); return generateServiceId(ns, protocol, service);
} }
public static class AddressEntry { public static class AddressEntry {
public InetSocketAddress addr; public InetSocketAddress addr;
public String nodeid; public String nodeid;
public long time; public long time;
public String resname; public String resname;
public AddressEntry refresh() { public AddressEntry refresh() {
this.time = System.currentTimeMillis(); this.time = System.currentTimeMillis();
return this; return this;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }
} }

View File

@@ -35,393 +35,393 @@ import org.redkale.util.*;
*/ */
public abstract class ClusterAgent { public abstract class ClusterAgent {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
@Resource(name = RESNAME_APP_NODEID) @Resource(name = RESNAME_APP_NODEID)
protected String nodeid; protected String nodeid;
@Resource(name = RESNAME_APP_NAME) @Resource(name = RESNAME_APP_NAME)
protected String appName = ""; protected String appName = "";
@Resource(name = RESNAME_APP_ADDR) @Resource(name = RESNAME_APP_ADDR)
protected InetSocketAddress appAddress; protected InetSocketAddress appAddress;
@Resource(required = false) @Resource(required = false)
protected Application application; protected Application application;
protected String name; protected String name;
protected boolean waits; protected boolean waits;
@Nullable @Nullable
protected String[] protocols; // 必须全大写 protected String[] protocols; // 必须全大写
protected int[] ports; protected int[] ports;
protected AnyValue config; protected AnyValue config;
protected Set<String> tags; protected Set<String> tags;
// key: serviceid // key: serviceid
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
// key: serviceid // key: serviceid
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
public void init(AnyValue config) { public void init(AnyValue config) {
this.config = config; this.config = config;
this.name = config.getValue("name", ""); this.name = config.getValue("name", "");
this.waits = config.getBoolValue("waits", false); this.waits = config.getBoolValue("waits", false);
String ps = config.getValue("protocols", "").toUpperCase(); String ps = config.getValue("protocols", "").toUpperCase();
this.protocols = Utility.isEmpty(ps) ? null : ps.split(";"); this.protocols = Utility.isEmpty(ps) ? null : ps.split(";");
String ts = config.getValue("ports", ""); String ts = config.getValue("ports", "");
if (ts != null && !ts.isEmpty()) { if (ts != null && !ts.isEmpty()) {
String[] its = ts.split(";"); String[] its = ts.split(";");
List<Integer> list = new ArrayList<>(); List<Integer> list = new ArrayList<>();
for (String str : its) { for (String str : its) {
if (str.trim().isEmpty()) { if (str.trim().isEmpty()) {
continue; continue;
} }
list.add(Integer.parseInt(str.trim())); list.add(Integer.parseInt(str.trim()));
} }
if (!list.isEmpty()) { if (!list.isEmpty()) {
this.ports = list.stream().mapToInt(x -> x).toArray(); this.ports = list.stream().mapToInt(x -> x).toArray();
} }
} }
Set<String> tags0 = new HashSet<>(); Set<String> tags0 = new HashSet<>();
for (String str : config.getValue("tags", "").split(";|,")) { for (String str : config.getValue("tags", "").split(";|,")) {
if (!str.trim().isEmpty()) { if (!str.trim().isEmpty()) {
tags0.add(str.trim()); tags0.add(str.trim());
} }
} }
if (!tags0.isEmpty()) { if (!tags0.isEmpty()) {
this.tags = tags0; this.tags = tags0;
} }
} }
@ResourceChanged @ResourceChanged
public abstract void onResourceChange(ResourceEvent[] events); public abstract void onResourceChange(ResourceEvent[] events);
public void destroy(AnyValue config) {} public void destroy(AnyValue config) {}
/** /**
* ServiceLoader时判断配置是否符合当前实现类 * ServiceLoader时判断配置是否符合当前实现类
* *
* @param config 节点配置 * @param config 节点配置
* @return boolean * @return boolean
*/ */
public abstract boolean acceptsConf(AnyValue config); public abstract boolean acceptsConf(AnyValue config);
public boolean containsProtocol(String protocol) { public boolean containsProtocol(String protocol) {
if (Utility.isEmpty(protocol)) { if (Utility.isEmpty(protocol)) {
return false; return false;
} }
return protocols == null || Utility.contains(protocols, protocol.toUpperCase()); return protocols == null || Utility.contains(protocols, protocol.toUpperCase());
} }
public boolean containsPort(int port) { public boolean containsPort(int port) {
if (ports == null || ports.length == 0) { if (ports == null || ports.length == 0) {
return true; return true;
} }
return Utility.contains(ports, port); return Utility.contains(ports, port);
} }
public void start() {} public void start() {}
public int intervalCheckSeconds() { public int intervalCheckSeconds() {
return 10; return 10;
} }
public abstract void register(Application application); public abstract void register(Application application);
public abstract void deregister(Application application); public abstract void deregister(Application application);
// 注册服务, 在NodeService调用Service.init方法之前调用 // 注册服务, 在NodeService调用Service.init方法之前调用
public void register( public void register(
NodeServer ns, NodeServer ns,
String protocol, String protocol,
Set<Service> localServices, Set<Service> localServices,
Set<Service> remoteServices, Set<Service> remoteServices,
Set<Service> servletServices) { Set<Service> servletServices) {
if (servletServices.isEmpty()) { if (servletServices.isEmpty()) {
return; return;
} }
// 注册本地模式 // 注册本地模式
for (Service service : servletServices) { for (Service service : servletServices) {
if (!canRegister(ns, protocol, service)) { if (!canRegister(ns, protocol, service)) {
continue; continue;
} }
ClusterEntry htentry = register(ns, protocol, service); ClusterEntry htentry = register(ns, protocol, service);
localEntrys.put(htentry.serviceid, htentry); localEntrys.put(htentry.serviceid, htentry);
} }
// 远程模式加载IP列表, 只支持SNCP协议 // 远程模式加载IP列表, 只支持SNCP协议
if (ns.isSNCP()) { if (ns.isSNCP()) {
for (Service service : remoteServices) { for (Service service : remoteServices) {
ClusterEntry entry = new ClusterEntry(ns, protocol, service); ClusterEntry entry = new ClusterEntry(ns, protocol, service);
updateSncpAddress(entry); updateSncpAddress(entry);
remoteEntrys.put(entry.serviceid, entry); remoteEntrys.put(entry.serviceid, entry);
} }
} }
} }
// 注销服务, 在NodeService调用Service.destroy 方法之前调用 // 注销服务, 在NodeService调用Service.destroy 方法之前调用
public void deregister( public void deregister(
NodeServer ns, NodeServer ns,
String protocol, String protocol,
Set<Service> localServices, Set<Service> localServices,
Set<Service> remoteServices, Set<Service> remoteServices,
Set<Service> servletServices) { Set<Service> servletServices) {
// 注销本地模式 远程模式不注册 // 注销本地模式 远程模式不注册
for (Service service : servletServices) { for (Service service : servletServices) {
if (!canRegister(ns, protocol, service)) { if (!canRegister(ns, protocol, service)) {
continue; continue;
} }
deregister(ns, protocol, service); deregister(ns, protocol, service);
} }
afterDeregister(ns, protocol); afterDeregister(ns, protocol);
} }
protected boolean canRegister(NodeServer ns, String protocol, Service service) { protected boolean canRegister(NodeServer ns, String protocol, Service service) {
if (service.getClass().getAnnotation(Component.class) != null) { if (service.getClass().getAnnotation(Component.class) != null) {
return false; return false;
} }
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) { if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) {
return false; return false;
} }
AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); AutoLoad al = service.getClass().getAnnotation(AutoLoad.class);
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) { if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) {
return false; return false;
} }
org.redkale.util.AutoLoad al2 = service.getClass().getAnnotation(org.redkale.util.AutoLoad.class); org.redkale.util.AutoLoad al2 = service.getClass().getAnnotation(org.redkale.util.AutoLoad.class);
if (al2 != null && !al2.value() && service.getClass().getAnnotation(Local.class) != null) { if (al2 != null && !al2.value() && service.getClass().getAnnotation(Local.class) != null) {
return false; return false;
} }
if (service instanceof WebSocketNode) { if (service instanceof WebSocketNode) {
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) { if (((WebSocketNode) service).getLocalWebSocketEngine() == null) {
return false; return false;
} }
} }
ClusterEntry entry = new ClusterEntry(ns, protocol, service); ClusterEntry entry = new ClusterEntry(ns, protocol, service);
if (entry.serviceName.trim().endsWith(".")) { if (entry.serviceName.trim().endsWith(".")) {
return false; return false;
} }
return true; return true;
} }
protected void afterDeregister(NodeServer ns, String protocol) { protected void afterDeregister(NodeServer ns, String protocol) {
if (!this.waits) { if (!this.waits) {
return; return;
} }
int s = intervalCheckSeconds(); int s = intervalCheckSeconds();
if (s > 0) { // 暂停,弥补其他依赖本进程服务的周期偏差 if (s > 0) { // 暂停,弥补其他依赖本进程服务的周期偏差
Utility.sleep(s * 1000); Utility.sleep(s * 1000);
logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister"); logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister");
} }
} }
// 获取HTTP远程服务的可用ip列表 // 获取HTTP远程服务的可用ip列表
public abstract CompletableFuture<Set<InetSocketAddress>> queryHttpAddress( public abstract CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(
String protocol, String module, String resname); String protocol, String module, String resname);
// 获取SNCP远程服务的可用ip列表 restype: resourceType.getName() // 获取SNCP远程服务的可用ip列表 restype: resourceType.getName()
public abstract CompletableFuture<Set<InetSocketAddress>> querySncpAddress( public abstract CompletableFuture<Set<InetSocketAddress>> querySncpAddress(
String protocol, String restype, String resname); String protocol, String restype, String resname);
// 获取远程服务的可用ip列表 // 获取远程服务的可用ip列表
protected abstract CompletableFuture<Set<InetSocketAddress>> queryAddress(ClusterEntry entry); protected abstract CompletableFuture<Set<InetSocketAddress>> queryAddress(ClusterEntry entry);
// 注册服务 // 注册服务
protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service); protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service);
// 注销服务 // 注销服务
protected abstract void deregister(NodeServer ns, String protocol, Service service); protected abstract void deregister(NodeServer ns, String protocol, Service service);
// 格式: protocol:classtype-resourcename // 格式: protocol:classtype-resourcename
protected void updateSncpAddress(ClusterEntry entry) { protected void updateSncpAddress(ClusterEntry entry) {
if (application == null) { if (application == null) {
return; return;
} }
Service service = entry.serviceRef.get(); Service service = entry.serviceRef.get();
if (service == null) { if (service == null) {
return; return;
} }
try { try {
Set<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join(); Set<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
SncpRpcGroups rpcGroups = application.getSncpRpcGroups(); SncpRpcGroups rpcGroups = application.getSncpRpcGroups();
rpcGroups.putClusterAddress(entry.resourceid, addrs); rpcGroups.putClusterAddress(entry.resourceid, addrs);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, entry + " updateSncpAddress error", e); logger.log(Level.SEVERE, entry + " updateSncpAddress error", e);
} }
} }
protected String urlEncode(String value) { protected String urlEncode(String value) {
return value == null ? null : URLEncoder.encode(value, StandardCharsets.UTF_8); return value == null ? null : URLEncoder.encode(value, StandardCharsets.UTF_8);
} }
protected String generateApplicationServiceName() { protected String generateApplicationServiceName() {
return Utility.isEmpty(appName) ? "node" : appName; return Utility.isEmpty(appName) ? "node" : appName;
} }
protected String generateApplicationServiceType() { protected String generateApplicationServiceType() {
return "nodes"; return "nodes";
} }
protected String generateApplicationServiceId() { protected String generateApplicationServiceId() {
return generateApplicationServiceName() + "@" + this.nodeid; return generateApplicationServiceName() + "@" + this.nodeid;
} }
protected String generateApplicationCheckName() { protected String generateApplicationCheckName() {
return "check-" + generateApplicationServiceName(); return "check-" + generateApplicationServiceName();
} }
protected String generateApplicationCheckId() { protected String generateApplicationCheckId() {
return "check-" + generateApplicationServiceId(); return "check-" + generateApplicationServiceId();
} }
protected String generateApplicationHost() { protected String generateApplicationHost() {
return this.appAddress.getHostString(); return this.appAddress.getHostString();
} }
protected int generateApplicationPort() { protected int generateApplicationPort() {
return this.appAddress.getPort(); return this.appAddress.getPort();
} }
public String generateSncpServiceName(String protocol, String restype, String resname) { public String generateSncpServiceName(String protocol, String restype, String resname) {
return protocol.toLowerCase() + ":" + restype + (Utility.isEmpty(resname) ? "" : ("-" + resname)); return protocol.toLowerCase() + ":" + restype + (Utility.isEmpty(resname) ? "" : ("-" + resname));
} }
// 也会提供给HttpMessageClusterAgent适用 // 也会提供给HttpMessageClusterAgent适用
public String generateHttpServiceName(String protocol, String module, String resname) { public String generateHttpServiceName(String protocol, String module, String resname) {
return protocol.toLowerCase() + ":" + module + (Utility.isEmpty(resname) ? "" : ("-" + resname)); return protocol.toLowerCase() + ":" + module + (Utility.isEmpty(resname) ? "" : ("-" + resname));
} }
// 格式: protocol:classtype-resourcename // 格式: protocol:classtype-resourcename
protected String generateServiceName(NodeServer ns, String protocol, Service service) { protected String generateServiceName(NodeServer ns, String protocol, Service service) {
if (protocol.toLowerCase().startsWith("http")) { // HTTP使用RestService.name方式是为了与MessageClient中的module保持一致, if (protocol.toLowerCase().startsWith("http")) { // HTTP使用RestService.name方式是为了与MessageClient中的module保持一致,
// 因为HTTP依靠的url中的module无法知道Service类名 // 因为HTTP依靠的url中的module无法知道Service类名
String resname = Sncp.getResourceName(service); String resname = Sncp.getResourceName(service);
String module = Rest.getRestModule(service).toLowerCase(); String module = Rest.getRestModule(service).toLowerCase();
return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname)); return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname));
} }
if (!Sncp.isSncpDyn(service)) { if (!Sncp.isSncpDyn(service)) {
return protocol.toLowerCase() + ":" + service.getClass().getName(); return protocol.toLowerCase() + ":" + service.getClass().getName();
} }
String resname = Sncp.getResourceName(service); String resname = Sncp.getResourceName(service);
return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName()
+ (resname.isEmpty() ? "" : ("-" + resname)); + (resname.isEmpty() ? "" : ("-" + resname));
} }
// 格式: protocol:classtype-resourcename:nodeid // 格式: protocol:classtype-resourcename:nodeid
protected String generateServiceId(NodeServer ns, String protocol, Service service) { protected String generateServiceId(NodeServer ns, String protocol, Service service) {
return generateServiceName(ns, protocol, service) + "@" + this.nodeid; return generateServiceName(ns, protocol, service) + "@" + this.nodeid;
} }
protected String generateCheckName(NodeServer ns, String protocol, Service service) { protected String generateCheckName(NodeServer ns, String protocol, Service service) {
return "check-" + generateServiceName(ns, protocol, service); return "check-" + generateServiceName(ns, protocol, service);
} }
protected String generateCheckId(NodeServer ns, String protocol, Service service) { protected String generateCheckId(NodeServer ns, String protocol, Service service) {
return "check-" + generateServiceId(ns, protocol, service); return "check-" + generateServiceId(ns, protocol, service);
} }
protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() { protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() {
return localEntrys; return localEntrys;
} }
protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() { protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() {
return remoteEntrys; return remoteEntrys;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
@Nullable @Nullable
public String[] getProtocols() { public String[] getProtocols() {
return protocols; return protocols;
} }
public void setProtocols(String[] protocols) { public void setProtocols(String[] protocols) {
this.protocols = protocols; this.protocols = protocols;
} }
public int[] getPorts() { public int[] getPorts() {
return ports; return ports;
} }
public void setPorts(int[] ports) { public void setPorts(int[] ports) {
this.ports = ports; this.ports = ports;
} }
public AnyValue getConfig() { public AnyValue getConfig() {
return config; return config;
} }
public void setConfig(AnyValue config) { public void setConfig(AnyValue config) {
this.config = config; this.config = config;
} }
public class ClusterEntry { public class ClusterEntry {
// serviceName+nodeid为主 服务的单个实例 // serviceName+nodeid为主 服务的单个实例
public String serviceid; public String serviceid;
// 以协议+Rest资源名为主 服务类名 // 以协议+Rest资源名为主 服务类名
public String serviceName; public String serviceName;
public final String resourceType; public final String resourceType;
public final String resourceName; public final String resourceName;
public final String resourceid; public final String resourceid;
public String checkid; public String checkid;
public String checkName; public String checkName;
// http or sncp // http or sncp
public String protocol; public String protocol;
// TCP or UDP // TCP or UDP
public String netProtocol; public String netProtocol;
@ConvertDisabled @ConvertDisabled
public WeakReference<Service> serviceRef; public WeakReference<Service> serviceRef;
public InetSocketAddress address; public InetSocketAddress address;
public boolean canceled; public boolean canceled;
public ClusterEntry(NodeServer ns, String protocol, Service service) { public ClusterEntry(NodeServer ns, String protocol, Service service) {
this.serviceid = generateServiceId(ns, protocol, service); this.serviceid = generateServiceId(ns, protocol, service);
this.serviceName = generateServiceName(ns, protocol, service); this.serviceName = generateServiceName(ns, protocol, service);
this.checkid = generateCheckId(ns, protocol, service); this.checkid = generateCheckId(ns, protocol, service);
this.checkName = generateCheckName(ns, protocol, service); this.checkName = generateCheckName(ns, protocol, service);
Class restype = Sncp.getResourceType(service); Class restype = Sncp.getResourceType(service);
this.resourceType = restype.getName(); this.resourceType = restype.getName();
this.resourceName = Sncp.getResourceName(service); this.resourceName = Sncp.getResourceName(service);
this.resourceid = Sncp.resourceid(resourceName, restype); this.resourceid = Sncp.resourceid(resourceName, restype);
this.protocol = protocol; this.protocol = protocol;
InetSocketAddress addr = ns.getSocketAddress(); InetSocketAddress addr = ns.getSocketAddress();
String host = addr.getHostString(); String host = addr.getHostString();
if ("0.0.0.0".equals(host)) { if ("0.0.0.0".equals(host)) {
host = appAddress.getHostString(); host = appAddress.getHostString();
addr = new InetSocketAddress(host, addr.getPort()); addr = new InetSocketAddress(host, addr.getPort());
} }
this.address = addr; this.address = addr;
this.serviceRef = new WeakReference(service); this.serviceRef = new WeakReference(service);
Server server = ns.getServer(); Server server = ns.getServer();
this.netProtocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : "TCP"; this.netProtocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : "TCP";
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }
} }

View File

@@ -23,231 +23,231 @@ import org.redkale.util.RedkaleClassLoader;
/** @author zhangjx */ /** @author zhangjx */
public class ClusterModuleEngine extends ModuleEngine { public class ClusterModuleEngine extends ModuleEngine {
// 第三方服务配置资源 // 第三方服务配置资源
// @since 2.8.0 // @since 2.8.0
private Properties clusterProperties = new Properties(); private Properties clusterProperties = new Properties();
// 第三方服务发现管理接口 // 第三方服务发现管理接口
// @since 2.1.0 // @since 2.1.0
private ClusterAgent clusterAgent; private ClusterAgent clusterAgent;
public ClusterModuleEngine(Application application) { public ClusterModuleEngine(Application application) {
super(application); super(application);
} }
/** 结束Application.init方法前被调用 */ /** 结束Application.init方法前被调用 */
@Override @Override
public void onAppPostInit() { public void onAppPostInit() {
ClusterAgent cluster = null; ClusterAgent cluster = null;
AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster"); AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster");
if (clusterConf != null) { if (clusterConf != null) {
try { try {
String classVal = environment.getPropertyValue( String classVal = environment.getPropertyValue(
clusterConf.getValue("type", clusterConf.getValue("value"))); // 兼容value字段 clusterConf.getValue("type", clusterConf.getValue("value"))); // 兼容value字段
if (classVal == null if (classVal == null
|| classVal.isEmpty() || classVal.isEmpty()
|| classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: consul, nacos || classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: consul, nacos
Iterator<ClusterAgentProvider> it = ServiceLoader.load( Iterator<ClusterAgentProvider> it = ServiceLoader.load(
ClusterAgentProvider.class, application.getClassLoader()) ClusterAgentProvider.class, application.getClassLoader())
.iterator(); .iterator();
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class); RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
while (it.hasNext()) { while (it.hasNext()) {
ClusterAgentProvider provider = it.next(); ClusterAgentProvider provider = it.next();
if (provider != null) { if (provider != null) {
RedkaleClassLoader.putReflectionPublicConstructors( RedkaleClassLoader.putReflectionPublicConstructors(
provider.getClass(), provider.getClass().getName()); // loader class provider.getClass(), provider.getClass().getName()); // loader class
} }
if (provider != null && provider.acceptsConf(clusterConf)) { if (provider != null && provider.acceptsConf(clusterConf)) {
cluster = provider.createInstance(); cluster = provider.createInstance();
cluster.setConfig(clusterConf); cluster.setConfig(clusterConf);
break; break;
} }
} }
if (cluster == null) { if (cluster == null) {
ClusterAgent cacheClusterAgent = new CacheClusterAgent(); ClusterAgent cacheClusterAgent = new CacheClusterAgent();
if (cacheClusterAgent.acceptsConf(clusterConf)) { if (cacheClusterAgent.acceptsConf(clusterConf)) {
cluster = cacheClusterAgent; cluster = cacheClusterAgent;
cluster.setConfig(clusterConf); cluster.setConfig(clusterConf);
} }
} }
if (cluster == null) { if (cluster == null) {
logger.log( logger.log(
Level.SEVERE, Level.SEVERE,
"load application cluster resource, but not found name='type' value error: " "load application cluster resource, but not found name='type' value error: "
+ clusterConf); + clusterConf);
} }
} else { } else {
Class type = application.getClassLoader().loadClass(classVal); Class type = application.getClassLoader().loadClass(classVal);
if (!ClusterAgent.class.isAssignableFrom(type)) { if (!ClusterAgent.class.isAssignableFrom(type)) {
logger.log( logger.log(
Level.SEVERE, Level.SEVERE,
"load application cluster resource, but not found " + ClusterAgent.class.getSimpleName() "load application cluster resource, but not found " + ClusterAgent.class.getSimpleName()
+ " implements class error: " + clusterConf); + " implements class error: " + clusterConf);
} else { } else {
RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName()); RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName());
cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance(); cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance();
cluster.setConfig(clusterConf); cluster.setConfig(clusterConf);
} }
} }
// 此时不能执行cluster.init因内置的对象可能依赖config.properties配置项 // 此时不能执行cluster.init因内置的对象可能依赖config.properties配置项
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e); logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e);
} }
} }
this.clusterAgent = cluster; this.clusterAgent = cluster;
if (this.clusterAgent != null) { if (this.clusterAgent != null) {
if (logger.isLoggable(Level.FINER)) { if (logger.isLoggable(Level.FINER)) {
logger.log( logger.log(
Level.FINER, Level.FINER,
"ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") initing"); "ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") initing");
} }
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
if (this.clusterAgent instanceof CacheClusterAgent) { if (this.clusterAgent instanceof CacheClusterAgent) {
String sourceName = String sourceName =
((CacheClusterAgent) clusterAgent).getSourceName(); // 必须在inject前调用需要赋值Resourcable.name ((CacheClusterAgent) clusterAgent).getSourceName(); // 必须在inject前调用需要赋值Resourcable.name
SourceManager sourceManager = application.getResourceFactory().find(SourceManager.class); SourceManager sourceManager = application.getResourceFactory().find(SourceManager.class);
sourceManager.loadCacheSource(sourceName, false); sourceManager.loadCacheSource(sourceName, false);
} }
this.resourceFactory.inject(clusterAgent); this.resourceFactory.inject(clusterAgent);
clusterAgent.init(clusterAgent.getConfig()); clusterAgent.init(clusterAgent.getConfig());
this.resourceFactory.register(ClusterAgent.class, clusterAgent); this.resourceFactory.register(ClusterAgent.class, clusterAgent);
logger.info("ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") init in " logger.info("ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") init in "
+ (System.currentTimeMillis() - s) + " ms"); + (System.currentTimeMillis() - s) + " ms");
} }
} }
/** 配置项加载后被调用 */ /** 配置项加载后被调用 */
@Override @Override
public void onEnvironmentLoaded(Properties allProps) { public void onEnvironmentLoaded(Properties allProps) {
allProps.forEach((key, val) -> { allProps.forEach((key, val) -> {
if (key.toString().startsWith("redkale.cluster.")) { if (key.toString().startsWith("redkale.cluster.")) {
this.clusterProperties.put(key, val); this.clusterProperties.put(key, val);
} }
}); });
} }
/** /**
* 配置项变更时被调用 * 配置项变更时被调用
* *
* @param namespace 命名空间 * @param namespace 命名空间
* @param events 变更项 * @param events 变更项
*/ */
@Override @Override
public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) { public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
Set<String> clusterRemovedKeys = new HashSet<>(); Set<String> clusterRemovedKeys = new HashSet<>();
Properties clusterChangedProps = new Properties(); Properties clusterChangedProps = new Properties();
for (ResourceEvent<String> event : events) { for (ResourceEvent<String> event : events) {
if (event.name().startsWith("redkale.cluster.")) { if (event.name().startsWith("redkale.cluster.")) {
if (!Objects.equals(event.newValue(), this.clusterProperties.getProperty(event.name()))) { if (!Objects.equals(event.newValue(), this.clusterProperties.getProperty(event.name()))) {
if (event.newValue() == null) { if (event.newValue() == null) {
if (this.clusterProperties.containsKey(event.name())) { if (this.clusterProperties.containsKey(event.name())) {
clusterRemovedKeys.add(event.name()); clusterRemovedKeys.add(event.name());
} }
} else { } else {
clusterChangedProps.put(event.name(), event.newValue()); clusterChangedProps.put(event.name(), event.newValue());
} }
} }
} }
} }
// 第三方服务注册配置项的变更 // 第三方服务注册配置项的变更
if (!clusterChangedProps.isEmpty() || !clusterRemovedKeys.isEmpty()) { if (!clusterChangedProps.isEmpty() || !clusterRemovedKeys.isEmpty()) {
if (this.clusterAgent != null) { if (this.clusterAgent != null) {
final AnyValueWriter old = final AnyValueWriter old =
(AnyValueWriter) application.getAppConfig().getAnyValue("cluster"); (AnyValueWriter) application.getAppConfig().getAnyValue("cluster");
Properties newProps = new Properties(); Properties newProps = new Properties();
newProps.putAll(clusterProperties); newProps.putAll(clusterProperties);
List<ResourceEvent> changeEvents = new ArrayList<>(); List<ResourceEvent> changeEvents = new ArrayList<>();
clusterChangedProps.forEach((k, v) -> { clusterChangedProps.forEach((k, v) -> {
final String key = k.toString(); final String key = k.toString();
newProps.put(k, v); newProps.put(k, v);
changeEvents.add(ResourceEvent.create( changeEvents.add(ResourceEvent.create(
key.substring("redkale.cluster.".length()), v, this.clusterProperties.getProperty(key))); key.substring("redkale.cluster.".length()), v, this.clusterProperties.getProperty(key)));
}); });
clusterRemovedKeys.forEach(k -> { clusterRemovedKeys.forEach(k -> {
final String key = k; final String key = k;
newProps.remove(k); newProps.remove(k);
changeEvents.add(ResourceEvent.create( changeEvents.add(ResourceEvent.create(
key.substring("redkale.cluster.".length()), null, this.clusterProperties.getProperty(key))); key.substring("redkale.cluster.".length()), null, this.clusterProperties.getProperty(key)));
}); });
if (!changeEvents.isEmpty()) { if (!changeEvents.isEmpty()) {
AnyValueWriter back = old.copy(); AnyValueWriter back = old.copy();
try { try {
old.replace(AnyValue.loadFromProperties(newProps) old.replace(AnyValue.loadFromProperties(newProps)
.getAnyValue("redkale") .getAnyValue("redkale")
.getAnyValue("cluster")); .getAnyValue("cluster"));
clusterAgent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()])); clusterAgent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()]));
} catch (RuntimeException e) { } catch (RuntimeException e) {
old.replace(back); // 还原配置 old.replace(back); // 还原配置
throw e; throw e;
} }
} }
} else { } else {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
clusterChangedProps.forEach((k, v) -> { clusterChangedProps.forEach((k, v) -> {
sb.append(ClusterAgent.class.getSimpleName()) sb.append(ClusterAgent.class.getSimpleName())
.append(" skip change '") .append(" skip change '")
.append(k) .append(k)
.append("'\r\n"); .append("'\r\n");
}); });
clusterRemovedKeys.forEach(k -> { clusterRemovedKeys.forEach(k -> {
sb.append(ClusterAgent.class.getSimpleName()) sb.append(ClusterAgent.class.getSimpleName())
.append(" skip change '") .append(" skip change '")
.append(k) .append(k)
.append("'\r\n"); .append("'\r\n");
}); });
if (sb.length() > 0) { if (sb.length() > 0) {
logger.log(Level.INFO, sb.toString()); logger.log(Level.INFO, sb.toString());
} }
} }
clusterRemovedKeys.forEach(k -> this.clusterProperties.remove(k)); clusterRemovedKeys.forEach(k -> this.clusterProperties.remove(k));
this.clusterProperties.putAll(clusterChangedProps); this.clusterProperties.putAll(clusterChangedProps);
} }
} }
/** /**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项 * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
* *
* @param path 配置项路径 * @param path 配置项路径
* @param key 配置项名称 * @param key 配置项名称
* @param val1 配置项原值 * @param val1 配置项原值
* @param val2 配置项新值 * @param val2 配置项新值
* @return MergeEnum * @return MergeEnum
*/ */
@Override @Override
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) { public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
if ("".equals(path) && "cluster".equals(key)) { if ("".equals(path) && "cluster".equals(key)) {
return AnyValue.MergeEnum.REPLACE; return AnyValue.MergeEnum.REPLACE;
} }
return null; return null;
} }
/** 进入Application.start方法被调用 */ /** 进入Application.start方法被调用 */
@Override @Override
public void onAppPreStart() { public void onAppPreStart() {
if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) { if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) {
this.clusterAgent.register(application); this.clusterAgent.register(application);
} }
} }
/** 服务全部启动后被调用 */ /** 服务全部启动后被调用 */
public void onServersPostStart() { public void onServersPostStart() {
if (this.clusterAgent != null) { if (this.clusterAgent != null) {
this.clusterAgent.start(); this.clusterAgent.start();
} }
} }
/** 服务全部停掉后被调用 */ /** 服务全部停掉后被调用 */
public void onServersPostStop() { public void onServersPostStop() {
if (!application.isCompileMode() && clusterAgent != null) { if (!application.isCompileMode() && clusterAgent != null) {
if (logger.isLoggable(Level.FINER)) { if (logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "ClusterAgent destroying"); logger.log(Level.FINER, "ClusterAgent destroying");
} }
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
clusterAgent.deregister(application); clusterAgent.deregister(application);
clusterAgent.destroy(clusterAgent.getConfig()); clusterAgent.destroy(clusterAgent.getConfig());
logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms"); logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms");
} }
} }
} }

View File

@@ -28,201 +28,201 @@ import org.redkale.util.Utility;
*/ */
public class HttpClusterRpcClient extends HttpRpcClient { public class HttpClusterRpcClient extends HttpRpcClient {
// jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET // jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET
private static final Set<String> DISALLOWED_HEADERS_SET = Utility.ofSet( private static final Set<String> DISALLOWED_HEADERS_SET = Utility.ofSet(
"connection", "connection",
"content-length", "content-length",
"date", "date",
"expect", "expect",
"from", "from",
"host", "host",
"origin", "origin",
"referer", "referer",
"upgrade", "upgrade",
"via", "via",
"warning"); "warning");
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
protected final HttpLocalRpcClient localClient; protected final HttpLocalRpcClient localClient;
protected final ConcurrentHashMap<String, Boolean> topicServletMap = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, Boolean> topicServletMap = new ConcurrentHashMap<>();
protected ClusterAgent clusterAgent; protected ClusterAgent clusterAgent;
@Resource(name = "cluster.httpClient", required = false) @Resource(name = "cluster.httpClient", required = false)
protected WebClient webClient; protected WebClient webClient;
@Resource(name = "cluster.httpClient", required = false) @Resource(name = "cluster.httpClient", required = false)
protected java.net.http.HttpClient httpClient; protected java.net.http.HttpClient httpClient;
public HttpClusterRpcClient(Application application, String resourceName, ClusterAgent clusterAgent) { public HttpClusterRpcClient(Application application, String resourceName, ClusterAgent clusterAgent) {
Objects.requireNonNull(clusterAgent); Objects.requireNonNull(clusterAgent);
this.localClient = new HttpLocalRpcClient(application, resourceName); this.localClient = new HttpLocalRpcClient(application, resourceName);
this.clusterAgent = clusterAgent; this.clusterAgent = clusterAgent;
} }
@Override @Override
protected String getNodeid() { protected String getNodeid() {
return localClient.getNodeid(); return localClient.getNodeid();
} }
@Override @Override
public CompletableFuture<HttpResult<byte[]>> sendMessage( public CompletableFuture<HttpResult<byte[]>> sendMessage(
String topic, Serializable userid, String groupid, WebRequest request) { String topic, Serializable userid, String groupid, WebRequest request) {
if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) { if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) {
return localClient.sendMessage(topic, userid, groupid, request); return localClient.sendMessage(topic, userid, groupid, request);
} else { } else {
return httpAsync(false, userid, request); return httpAsync(false, userid, request);
} }
} }
@Override @Override
public CompletableFuture<Void> produceMessage( public CompletableFuture<Void> produceMessage(
String topic, Serializable userid, String groupid, WebRequest request) { String topic, Serializable userid, String groupid, WebRequest request) {
if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) { if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) {
return localClient.produceMessage(topic, userid, groupid, request); return localClient.produceMessage(topic, userid, groupid, request);
} else { } else {
return httpAsync(true, userid, request).thenApply(v -> null); return httpAsync(true, userid, request).thenApply(v -> null);
} }
} }
private CompletableFuture<HttpResult<byte[]>> httpAsync(boolean produce, Serializable userid, WebRequest req) { private CompletableFuture<HttpResult<byte[]>> httpAsync(boolean produce, Serializable userid, WebRequest req) {
req.setTraceid(Traces.computeIfAbsent(req.getTraceid(), Traces.currentTraceid())); req.setTraceid(Traces.computeIfAbsent(req.getTraceid(), Traces.currentTraceid()));
String module = req.getPath(); String module = req.getPath();
module = module.substring(1, module.indexOf('/', 1)); module = module.substring(1, module.indexOf('/', 1));
HttpHeaders headers = req.getHeaders(); HttpHeaders headers = req.getHeaders();
String resname = req.getHeader(Rest.REST_HEADER_RESNAME, ""); String resname = req.getHeader(Rest.REST_HEADER_RESNAME, "");
final String localModule = module; final String localModule = module;
if (logger.isLoggable(Level.FINEST)) { if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "httpAsync.queryHttpAddress: module=" + localModule + ", resname=" + resname); logger.log(Level.FINEST, "httpAsync.queryHttpAddress: module=" + localModule + ", resname=" + resname);
} }
return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> { return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> {
Traces.currentTraceid(req.getTraceid()); Traces.currentTraceid(req.getTraceid());
if (isEmpty(addrs)) { if (isEmpty(addrs)) {
if (logger.isLoggable(Level.WARNING)) { if (logger.isLoggable(Level.WARNING)) {
logger.log( logger.log(
Level.WARNING, Level.WARNING,
"httpAsync." + (produce ? "produceMessage" : "sendMessage") + " failed, module=" "httpAsync." + (produce ? "produceMessage" : "sendMessage") + " failed, module="
+ localModule + ", resname=" + resname + ", address is empty"); + localModule + ", resname=" + resname + ", address is empty");
} }
return new HttpResult<byte[]>().status(404).toFuture(); return new HttpResult<byte[]>().status(404).toFuture();
} }
final HttpHeaders clientHeaders = HttpHeaders.create(); final HttpHeaders clientHeaders = HttpHeaders.create();
if (headers != null) { if (headers != null) {
boolean ws = headers.contains("Sec-WebSocket-Key"); boolean ws = headers.contains("Sec-WebSocket-Key");
headers.forEach((n, v) -> { headers.forEach((n, v) -> {
if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase()) if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())
&& (!ws && (!ws
|| (!"Connection".equals(n) || (!"Connection".equals(n)
&& !"Sec-WebSocket-Key".equals(n) && !"Sec-WebSocket-Key".equals(n)
&& !"Sec-WebSocket-Version".equals(n)))) { && !"Sec-WebSocket-Version".equals(n)))) {
clientHeaders.add(n, v); clientHeaders.add(n, v);
} }
}); });
} }
clientHeaders.set("Content-Type", "x-www-form-urlencoded"); clientHeaders.set("Content-Type", "x-www-form-urlencoded");
if (req.isRpc()) { if (req.isRpc()) {
clientHeaders.set(Rest.REST_HEADER_RPC, "true"); clientHeaders.set(Rest.REST_HEADER_RPC, "true");
} }
if (isNotEmpty(req.getTraceid())) { if (isNotEmpty(req.getTraceid())) {
clientHeaders.set(Rest.REST_HEADER_TRACEID, req.getTraceid()); clientHeaders.set(Rest.REST_HEADER_TRACEID, req.getTraceid());
} }
if (userid != null) { if (userid != null) {
clientHeaders.set(Rest.REST_HEADER_CURRUSERID, String.valueOf(userid)); clientHeaders.set(Rest.REST_HEADER_CURRUSERID, String.valueOf(userid));
} }
if (req.getReqConvertType() != null) { if (req.getReqConvertType() != null) {
clientHeaders.set( clientHeaders.set(
Rest.REST_HEADER_REQ_CONVERT, req.getReqConvertType().toString()); Rest.REST_HEADER_REQ_CONVERT, req.getReqConvertType().toString());
} }
if (req.getRespConvertType() != null) { if (req.getRespConvertType() != null) {
clientHeaders.set( clientHeaders.set(
Rest.REST_HEADER_RESP_CONVERT, req.getRespConvertType().toString()); Rest.REST_HEADER_RESP_CONVERT, req.getRespConvertType().toString());
} }
if (webClient != null) { if (webClient != null) {
WebRequest newReq = req.copy().headers(clientHeaders); WebRequest newReq = req.copy().headers(clientHeaders);
InetSocketAddress addr = randomAddress(newReq, addrs); InetSocketAddress addr = randomAddress(newReq, addrs);
if (logger.isLoggable(Level.FINEST)) { if (logger.isLoggable(Level.FINEST)) {
logger.log( logger.log(
Level.FINEST, Level.FINEST,
"httpAsync: module=" + localModule + ", resname=" + resname + ", addr=" + addr); "httpAsync: module=" + localModule + ", resname=" + resname + ", addr=" + addr);
} }
return (CompletableFuture) webClient.sendAsync(addr, newReq); return (CompletableFuture) webClient.sendAsync(addr, newReq);
} }
byte[] clientBody = null; byte[] clientBody = null;
if (isNotEmpty(req.getBody())) { if (isNotEmpty(req.getBody())) {
String paramstr = req.getParametersToString(); String paramstr = req.getParametersToString();
if (paramstr != null) { if (paramstr != null) {
if (req.getPath().indexOf('?') > 0) { if (req.getPath().indexOf('?') > 0) {
req.setPath(req.getPath() + "&" + paramstr); req.setPath(req.getPath() + "&" + paramstr);
} else { } else {
req.setPath(req.getPath() + "?" + paramstr); req.setPath(req.getPath() + "?" + paramstr);
} }
} }
clientBody = req.getBody(); clientBody = req.getBody();
} else { } else {
String paramstr = req.getParametersToString(); String paramstr = req.getParametersToString();
if (paramstr != null) { if (paramstr != null) {
clientBody = paramstr.getBytes(StandardCharsets.UTF_8); clientBody = paramstr.getBytes(StandardCharsets.UTF_8);
} }
} }
if (logger.isLoggable(Level.FINEST)) { if (logger.isLoggable(Level.FINEST)) {
logger.log( logger.log(
Level.FINEST, Level.FINEST,
"httpAsync: module=" + localModule + ", resname=" + resname + ", enter sendEachAddressAsync"); "httpAsync: module=" + localModule + ", resname=" + resname + ", enter sendEachAddressAsync");
} }
return sendEachAddressAsync(req, req.requestPath(), clientHeaders, clientBody, addrs.iterator()); return sendEachAddressAsync(req, req.requestPath(), clientHeaders, clientBody, addrs.iterator());
}); });
} }
protected InetSocketAddress randomAddress(WebRequest req, Set<InetSocketAddress> addrs) { protected InetSocketAddress randomAddress(WebRequest req, Set<InetSocketAddress> addrs) {
InetSocketAddress[] array = addrs.toArray(new InetSocketAddress[addrs.size()]); InetSocketAddress[] array = addrs.toArray(new InetSocketAddress[addrs.size()]);
return array[ThreadLocalRandom.current().nextInt(array.length)]; return array[ThreadLocalRandom.current().nextInt(array.length)];
} }
protected CompletableFuture<HttpResult<byte[]>> sendEachAddressAsync( protected CompletableFuture<HttpResult<byte[]>> sendEachAddressAsync(
WebRequest req, WebRequest req,
String requestPath, String requestPath,
final HttpHeaders clientHeaders, final HttpHeaders clientHeaders,
byte[] clientBody, byte[] clientBody,
Iterator<InetSocketAddress> it) { Iterator<InetSocketAddress> it) {
if (!it.hasNext()) { if (!it.hasNext()) {
return new HttpResult<byte[]>().status(404).toFuture(); return new HttpResult<byte[]>().status(404).toFuture();
} }
InetSocketAddress addr = it.next(); InetSocketAddress addr = it.next();
String host = addr.getPort() > 0 && addr.getPort() != 80 String host = addr.getPort() > 0 && addr.getPort() != 80
? (addr.getHostString() + ":" + addr.getPort()) ? (addr.getHostString() + ":" + addr.getPort())
: addr.getHostString(); : addr.getHostString();
String url = "http://" + host + requestPath; String url = "http://" + host + requestPath;
if (logger.isLoggable(Level.FINER)) { if (logger.isLoggable(Level.FINER)) {
logger.log( logger.log(
Level.FINER, Level.FINER,
"sendEachAddressAsync: url: " + url + ", body: " "sendEachAddressAsync: url: " + url + ", body: "
+ (clientBody != null ? new String(clientBody, StandardCharsets.UTF_8) : "") + ", headers: " + (clientBody != null ? new String(clientBody, StandardCharsets.UTF_8) : "") + ", headers: "
+ clientHeaders); + clientHeaders);
} }
java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder() java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder()
.uri(URI.create(url)) .uri(URI.create(url))
.timeout(Duration.ofMillis(10_000)) .timeout(Duration.ofMillis(10_000))
// 存在sendHeader后不发送body数据的问题 java.net.http.HttpRequest的bug? // 存在sendHeader后不发送body数据的问题 java.net.http.HttpRequest的bug?
.method("POST", createBodyPublisher(clientBody)); .method("POST", createBodyPublisher(clientBody));
clientHeaders.forEach(builder::header); clientHeaders.forEach(builder::header);
return httpClient return httpClient
.sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()) .sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray())
.thenApply((java.net.http.HttpResponse<byte[]> resp) -> { .thenApply((java.net.http.HttpResponse<byte[]> resp) -> {
Traces.currentTraceid(req.getTraceid()); Traces.currentTraceid(req.getTraceid());
final int rs = resp.statusCode(); final int rs = resp.statusCode();
if (rs != 200) { if (rs != 200) {
return new HttpResult<byte[]>().status(rs); return new HttpResult<byte[]>().status(rs);
} }
return new HttpResult<>(resp.body()); return new HttpResult<>(resp.body());
}); });
} }
private static java.net.http.HttpRequest.BodyPublisher createBodyPublisher(byte[] clientBody) { private static java.net.http.HttpRequest.BodyPublisher createBodyPublisher(byte[] clientBody) {
return clientBody == null return clientBody == null
? java.net.http.HttpRequest.BodyPublishers.noBody() ? java.net.http.HttpRequest.BodyPublishers.noBody()
: java.net.http.HttpRequest.BodyPublishers.ofByteArray(clientBody); : java.net.http.HttpRequest.BodyPublishers.ofByteArray(clientBody);
} }
} }

View File

@@ -32,320 +32,320 @@ import org.redkale.util.Traces;
*/ */
public class HttpLocalRpcClient extends HttpRpcClient { public class HttpLocalRpcClient extends HttpRpcClient {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
protected final Application application; protected final Application application;
protected final String resourceName; protected final String resourceName;
protected HttpServer currServer; protected HttpServer currServer;
public HttpLocalRpcClient(Application application, String resourceName) { public HttpLocalRpcClient(Application application, String resourceName) {
this.application = application; this.application = application;
this.resourceName = resourceName; this.resourceName = resourceName;
} }
private HttpServer httpServer() { private HttpServer httpServer() {
if (this.currServer == null) { if (this.currServer == null) {
NodeHttpServer nodeHttpServer = null; NodeHttpServer nodeHttpServer = null;
List<NodeServer> nodeServers = application.getNodeServers(); List<NodeServer> nodeServers = application.getNodeServers();
for (NodeServer n : nodeServers) { for (NodeServer n : nodeServers) {
if (n.getClass() == NodeHttpServer.class if (n.getClass() == NodeHttpServer.class
&& Objects.equals( && Objects.equals(
resourceName, resourceName,
((NodeHttpServer) n).getHttpServer().getName())) { ((NodeHttpServer) n).getHttpServer().getName())) {
nodeHttpServer = (NodeHttpServer) n; nodeHttpServer = (NodeHttpServer) n;
break; break;
} }
} }
if (nodeHttpServer == null) { if (nodeHttpServer == null) {
for (NodeServer n : nodeServers) { for (NodeServer n : nodeServers) {
if (n.getClass() == NodeHttpServer.class) { if (n.getClass() == NodeHttpServer.class) {
nodeHttpServer = (NodeHttpServer) n; nodeHttpServer = (NodeHttpServer) n;
break; break;
} }
} }
} }
if (nodeHttpServer == null) { if (nodeHttpServer == null) {
throw new HttpException("Not found HttpServer"); throw new HttpException("Not found HttpServer");
} }
this.currServer = nodeHttpServer.getServer(); this.currServer = nodeHttpServer.getServer();
} }
return this.currServer; return this.currServer;
} }
@Override @Override
protected String getNodeid() { protected String getNodeid() {
return application.getNodeid(); return application.getNodeid();
} }
protected HttpContext context() { protected HttpContext context() {
return httpServer().getContext(); return httpServer().getContext();
} }
protected HttpDispatcherServlet dispatcherServlet() { protected HttpDispatcherServlet dispatcherServlet() {
return (HttpDispatcherServlet) httpServer().getDispatcherServlet(); return (HttpDispatcherServlet) httpServer().getDispatcherServlet();
} }
public HttpServlet findHttpServlet(String topic) { public HttpServlet findHttpServlet(String topic) {
return dispatcherServlet().findServletByTopic(topic); return dispatcherServlet().findServletByTopic(topic);
} }
public HttpServlet findHttpServlet(WebRequest request) { public HttpServlet findHttpServlet(WebRequest request) {
return dispatcherServlet().findServletByTopic(generateHttpReqTopic(request, request.getContextPath())); return dispatcherServlet().findServletByTopic(generateHttpReqTopic(request, request.getContextPath()));
} }
@Override @Override
public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) { public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) {
return sendMessage((Serializable) null, (String) null, request, type); return sendMessage((Serializable) null, (String) null, request, type);
} }
@Override @Override
public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) { public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) {
return sendMessage(userid, (String) null, request, type); return sendMessage(userid, (String) null, request, type);
} }
@Override @Override
public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) { public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) {
if (isEmpty(request.getTraceid())) { if (isEmpty(request.getTraceid())) {
request.setTraceid(Traces.currentTraceid()); request.setTraceid(Traces.currentTraceid());
} }
CompletableFuture future = new CompletableFuture(); CompletableFuture future = new CompletableFuture();
String topic = generateHttpReqTopic(request, request.getContextPath()); String topic = generateHttpReqTopic(request, request.getContextPath());
HttpServlet servlet = findHttpServlet(topic); HttpServlet servlet = findHttpServlet(topic);
if (servlet == null) { if (servlet == null) {
if (logger.isLoggable(Level.FINE)) { if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet"); logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet");
} }
future.completeExceptionally(new HttpException("404 Not Found " + topic)); future.completeExceptionally(new HttpException("404 Not Found " + topic));
return future; return future;
} }
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid); HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
HttpResponse resp = new HttpMessageLocalResponse(req, future); HttpResponse resp = new HttpMessageLocalResponse(req, future);
try { try {
servlet.execute(req, resp); servlet.execute(req, resp);
} catch (Exception e) { } catch (Exception e) {
future.completeExceptionally(e); future.completeExceptionally(e);
} }
return future; return future;
} }
@Override @Override
public CompletableFuture<HttpResult<byte[]>> sendMessage( public CompletableFuture<HttpResult<byte[]>> sendMessage(
String topic, Serializable userid, String groupid, WebRequest request) { String topic, Serializable userid, String groupid, WebRequest request) {
if (isEmpty(request.getTraceid())) { if (isEmpty(request.getTraceid())) {
request.setTraceid(Traces.currentTraceid()); request.setTraceid(Traces.currentTraceid());
} }
CompletableFuture future = new CompletableFuture(); CompletableFuture future = new CompletableFuture();
HttpServlet servlet = findHttpServlet(topic); HttpServlet servlet = findHttpServlet(topic);
if (servlet == null) { if (servlet == null) {
if (logger.isLoggable(Level.FINE)) { if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet"); logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet");
} }
future.complete(new HttpResult().status(404)); future.complete(new HttpResult().status(404));
return future; return future;
} }
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid); HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
HttpResponse resp = new HttpMessageLocalResponse(req, future); HttpResponse resp = new HttpMessageLocalResponse(req, future);
try { try {
servlet.execute(req, resp); servlet.execute(req, resp);
} catch (Exception e) { } catch (Exception e) {
future.completeExceptionally(e); future.completeExceptionally(e);
} }
return future.thenApply(rs -> { return future.thenApply(rs -> {
Traces.currentTraceid(request.getTraceid()); Traces.currentTraceid(request.getTraceid());
if (rs == null) { if (rs == null) {
return new HttpResult(); return new HttpResult();
} }
if (rs instanceof HttpResult) { if (rs instanceof HttpResult) {
Object result = ((HttpResult) rs).getResult(); Object result = ((HttpResult) rs).getResult();
if (result == null || result instanceof byte[]) { if (result == null || result instanceof byte[]) {
return (HttpResult) rs; return (HttpResult) rs;
} }
return new HttpResult(JsonConvert.root().convertToBytes(result)); return new HttpResult(JsonConvert.root().convertToBytes(result));
} }
return new HttpResult(JsonConvert.root().convertToBytes(rs)); return new HttpResult(JsonConvert.root().convertToBytes(rs));
}); });
} }
@Override @Override
public CompletableFuture<Void> produceMessage( public CompletableFuture<Void> produceMessage(
String topic, Serializable userid, String groupid, WebRequest request) { String topic, Serializable userid, String groupid, WebRequest request) {
CompletableFuture future = new CompletableFuture(); CompletableFuture future = new CompletableFuture();
HttpDispatcherServlet ps = dispatcherServlet(); HttpDispatcherServlet ps = dispatcherServlet();
HttpServlet servlet = ps.findServletByTopic(topic); HttpServlet servlet = ps.findServletByTopic(topic);
if (servlet == null) { if (servlet == null) {
if (logger.isLoggable(Level.FINE)) { if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "produceMessage: request=" + request + ", not found servlet"); logger.log(Level.FINE, "produceMessage: request=" + request + ", not found servlet");
} }
future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); future.completeExceptionally(new RuntimeException("404 Not Found " + topic));
return future; return future;
} }
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid); HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
HttpResponse resp = new HttpMessageLocalResponse(req, null); HttpResponse resp = new HttpMessageLocalResponse(req, null);
try { try {
servlet.execute(req, resp); servlet.execute(req, resp);
} catch (Exception e) { } catch (Exception e) {
throw new RedkaleException(e); throw new RedkaleException(e);
} }
return future.thenApply(rs -> { return future.thenApply(rs -> {
Traces.currentTraceid(request.getTraceid()); Traces.currentTraceid(request.getTraceid());
return null; return null;
}); });
} }
public static class HttpMessageLocalRequest extends HttpRequest { public static class HttpMessageLocalRequest extends HttpRequest {
public HttpMessageLocalRequest(HttpContext context, WebRequest req, Serializable userid) { public HttpMessageLocalRequest(HttpContext context, WebRequest req, Serializable userid) {
super(context, req); super(context, req);
if (userid != null) { if (userid != null) {
this.currentUserid = userid; this.currentUserid = userid;
} }
} }
} }
public static class HttpMessageLocalResponse extends HttpResponse { public static class HttpMessageLocalResponse extends HttpResponse {
private final CompletableFuture future; private final CompletableFuture future;
public HttpMessageLocalResponse(HttpRequest req, CompletableFuture future) { public HttpMessageLocalResponse(HttpRequest req, CompletableFuture future) {
super(req.getContext(), req, null); super(req.getContext(), req, null);
this.future = future; this.future = future;
} }
@Override @Override
public void finishJson(final Convert convert, final Type type, final Object obj) { public void finishJson(final Convert convert, final Type type, final Object obj) {
if (future == null) { if (future == null) {
return; return;
} }
future.complete(obj); future.complete(obj);
} }
@Override @Override
public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) { public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) {
if (future == null) { if (future == null) {
return; return;
} }
future.complete(ret); future.complete(ret);
} }
@Override @Override
public void finish(final Convert convert, final Type type, Object obj) { public void finish(final Convert convert, final Type type, Object obj) {
if (future == null) { if (future == null) {
return; return;
} }
if (obj instanceof CompletableFuture) { if (obj instanceof CompletableFuture) {
((CompletableFuture) obj).whenComplete((r, t) -> { ((CompletableFuture) obj).whenComplete((r, t) -> {
if (t == null) { if (t == null) {
future.complete(r); future.complete(r);
} else { } else {
future.completeExceptionally((Throwable) t); future.completeExceptionally((Throwable) t);
} }
}); });
} else { } else {
future.complete(obj); future.complete(obj);
} }
} }
@Override @Override
public void finish(String obj) { public void finish(String obj) {
if (future == null) { if (future == null) {
return; return;
} }
future.complete(obj == null ? "" : obj); future.complete(obj == null ? "" : obj);
} }
@Override @Override
public void finish304() { public void finish304() {
finish(304, null); finish(304, null);
} }
@Override @Override
public void finish404() { public void finish404() {
finish(404, null); finish(404, null);
} }
@Override @Override
public void finish500() { public void finish500() {
finish(500, null); finish(500, null);
} }
@Override @Override
public void finish504() { public void finish504() {
finish(504, null); finish(504, null);
} }
@Override @Override
public void finish(int status, String msg) { public void finish(int status, String msg) {
if (future == null) { if (future == null) {
return; return;
} }
if (status == 0 || status == 200) { if (status == 0 || status == 200) {
future.complete(msg == null ? "" : msg); future.complete(msg == null ? "" : msg);
} else { } else {
future.complete(new HttpResult(msg == null ? "" : msg).status(status)); future.complete(new HttpResult(msg == null ? "" : msg).status(status));
} }
} }
@Override @Override
public void finish(final Convert convert, Type valueType, HttpResult result) { public void finish(final Convert convert, Type valueType, HttpResult result) {
if (future == null) { if (future == null) {
return; return;
} }
if (convert != null) { if (convert != null) {
result.convert(convert); result.convert(convert);
} }
future.complete(result); future.complete(result);
} }
@Override @Override
public void finish(boolean kill, final byte[] bs, int offset, int length) { public void finish(boolean kill, final byte[] bs, int offset, int length) {
if (future == null) { if (future == null) {
return; return;
} }
if (offset == 0 && bs.length == length) { if (offset == 0 && bs.length == length) {
future.complete(bs); future.complete(bs);
} else { } else {
future.complete(Arrays.copyOfRange(bs, offset, offset + length)); future.complete(Arrays.copyOfRange(bs, offset, offset + length));
} }
} }
@Override @Override
public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) {
if (future == null) { if (future == null) {
return; return;
} }
byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length); byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length);
future.complete(rs); future.complete(rs);
} }
@Override @Override
public void finishBuffer(boolean kill, ByteBuffer buffer) { public void finishBuffer(boolean kill, ByteBuffer buffer) {
if (future == null) { if (future == null) {
return; return;
} }
byte[] bs = new byte[buffer.remaining()]; byte[] bs = new byte[buffer.remaining()];
buffer.get(bs); buffer.get(bs);
future.complete(bs); future.complete(bs);
} }
@Override @Override
public void finishBuffers(boolean kill, ByteBuffer... buffers) { public void finishBuffers(boolean kill, ByteBuffer... buffers) {
if (future == null) { if (future == null) {
return; return;
} }
int size = 0; int size = 0;
for (ByteBuffer buf : buffers) { for (ByteBuffer buf : buffers) {
size += buf.remaining(); size += buf.remaining();
} }
byte[] bs = new byte[size]; byte[] bs = new byte[size];
int index = 0; int index = 0;
for (ByteBuffer buf : buffers) { for (ByteBuffer buf : buffers) {
int r = buf.remaining(); int r = buf.remaining();
buf.get(bs, index, r); buf.get(bs, index, r);
index += r; index += r;
} }
future.complete(bs); future.complete(bs);
} }
} }
} }

View File

@@ -21,61 +21,61 @@ import org.redkale.util.*;
*/ */
public class AnyDecoder<T> implements Decodeable<Reader, T> { public class AnyDecoder<T> implements Decodeable<Reader, T> {
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {}.getType(); private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {}.getType();
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {}.getType(); private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {}.getType();
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class); private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
private static final Creator<LinkedHashMap> mapCreator = Creator.create(LinkedHashMap.class); private static final Creator<LinkedHashMap> mapCreator = Creator.create(LinkedHashMap.class);
protected final Decodeable<Reader, ? extends CharSequence> stringDecoder; protected final Decodeable<Reader, ? extends CharSequence> stringDecoder;
protected final CollectionDecoder collectionDecoder; protected final CollectionDecoder collectionDecoder;
protected final MapDecoder mapDecoder; protected final MapDecoder mapDecoder;
/** /**
* 构造函数 * 构造函数
* *
* @param factory ConvertFactory * @param factory ConvertFactory
*/ */
public AnyDecoder(final ConvertFactory factory) { public AnyDecoder(final ConvertFactory factory) {
this(mapCreator, mapObjectType, collectionCreator, collectionObjectType, factory.loadDecoder(String.class)); this(mapCreator, mapObjectType, collectionCreator, collectionObjectType, factory.loadDecoder(String.class));
} }
protected AnyDecoder( protected AnyDecoder(
Creator<? extends Map> mapCreator, Creator<? extends Map> mapCreator,
Type mapObjectType, Type mapObjectType,
Creator<? extends Collection> listCreator, Creator<? extends Collection> listCreator,
Type listObjectType, Type listObjectType,
Decodeable<Reader, String> keyDecoder) { Decodeable<Reader, String> keyDecoder) {
this.stringDecoder = keyDecoder; this.stringDecoder = keyDecoder;
this.collectionDecoder = new CollectionDecoder(listObjectType, Object.class, listCreator, this); this.collectionDecoder = new CollectionDecoder(listObjectType, Object.class, listCreator, this);
this.mapDecoder = new MapDecoder(mapObjectType, String.class, Object.class, mapCreator, keyDecoder, this); this.mapDecoder = new MapDecoder(mapObjectType, String.class, Object.class, mapCreator, keyDecoder, this);
} }
@Override @Override
public T convertFrom(Reader in) { public T convertFrom(Reader in) {
ValueType vt = in.readType(); ValueType vt = in.readType();
if (vt == null) { if (vt == null) {
return null; return null;
} }
switch (vt) { switch (vt) {
case ARRAY: case ARRAY:
return (T) this.collectionDecoder.convertFrom(in); return (T) this.collectionDecoder.convertFrom(in);
case MAP: case MAP:
return (T) this.mapDecoder.convertFrom(in); return (T) this.mapDecoder.convertFrom(in);
} }
return (T) stringFrom(in); return (T) stringFrom(in);
} }
protected T stringFrom(Reader in) { protected T stringFrom(Reader in) {
return (T) this.stringDecoder.convertFrom(in); return (T) this.stringDecoder.convertFrom(in);
} }
@Override @Override
public Type getType() { public Type getType() {
return void.class; return void.class;
} }
} }

View File

@@ -17,39 +17,39 @@ import java.lang.reflect.Type;
*/ */
public final class AnyEncoder<T> implements Encodeable<Writer, T> { public final class AnyEncoder<T> implements Encodeable<Writer, T> {
final ConvertFactory factory; final ConvertFactory factory;
AnyEncoder(ConvertFactory factory) { AnyEncoder(ConvertFactory factory) {
this.factory = factory; this.factory = factory;
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void convertTo(final Writer out, final T value) { public void convertTo(final Writer out, final T value) {
if (value == null) { if (value == null) {
out.writeClassName(null); out.writeClassName(null);
out.writeNull(); out.writeNull();
} else { } else {
Class clazz = value.getClass(); Class clazz = value.getClass();
if (clazz == Object.class) { if (clazz == Object.class) {
out.writeObjectB(value); out.writeObjectB(value);
out.writeObjectE(value); out.writeObjectE(value);
return; return;
} }
if (out.needWriteClassName()) { if (out.needWriteClassName()) {
out.writeClassName(factory.getEntityAlias(clazz)); out.writeClassName(factory.getEntityAlias(clazz));
} }
factory.loadEncoder(clazz).convertTo(out, value); factory.loadEncoder(clazz).convertTo(out, value);
} }
} }
@Override @Override
public Type getType() { public Type getType() {
return Object.class; return Object.class;
} }
@Override @Override
public boolean specifyable() { public boolean specifyable() {
return false; return false;
} }
} }

View File

@@ -19,19 +19,19 @@ import org.redkale.util.AnyValue;
*/ */
public class AnyValueDecoder<R extends Reader> implements Decodeable<R, AnyValue> { public class AnyValueDecoder<R extends Reader> implements Decodeable<R, AnyValue> {
protected final ConvertFactory factory; protected final ConvertFactory factory;
public AnyValueDecoder(final ConvertFactory factory) { public AnyValueDecoder(final ConvertFactory factory) {
this.factory = factory; this.factory = factory;
} }
@Override @Override
public AnyValue convertFrom(R in) { public AnyValue convertFrom(R in) {
return null; return null;
} }
@Override @Override
public Type getType() { public Type getType() {
return AnyValue.class; return AnyValue.class;
} }
} }

View File

@@ -19,13 +19,13 @@ import org.redkale.util.AnyValue;
*/ */
public class AnyValueEncoder<W extends Writer> implements Encodeable<W, AnyValue> { public class AnyValueEncoder<W extends Writer> implements Encodeable<W, AnyValue> {
@Override @Override
public void convertTo(W out, AnyValue value) { public void convertTo(W out, AnyValue value) {
// do nothing // do nothing
} }
@Override @Override
public Type getType() { public Type getType() {
return AnyValue.class; return AnyValue.class;
} }
} }

View File

@@ -24,138 +24,138 @@ import org.redkale.util.Creator;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ArrayDecoder<T> implements Decodeable<Reader, T[]> { public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
protected final Type type; protected final Type type;
protected final Type componentType; protected final Type componentType;
protected final Class componentClass; protected final Class componentClass;
protected final Decodeable<Reader, T> componentDecoder; protected final Decodeable<Reader, T> componentDecoder;
protected final IntFunction<T[]> componentArrayFunction; protected final IntFunction<T[]> componentArrayFunction;
protected volatile boolean inited = false; protected volatile boolean inited = false;
private final ReentrantLock lock = new ReentrantLock(); private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition(); private final Condition condition = lock.newCondition();
public ArrayDecoder(final ConvertFactory factory, final Type type) { public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try { try {
if (type instanceof GenericArrayType) { if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType(); Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t; this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) { } else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType(); this.componentType = ((Class) type).getComponentType();
} else { } else {
throw new ConvertException("(" + type + ") is not a array type"); throw new ConvertException("(" + type + ") is not a array type");
} }
if (this.componentType instanceof ParameterizedType) { if (this.componentType instanceof ParameterizedType) {
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType(); this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
} else { } else {
this.componentClass = (Class) this.componentType; this.componentClass = (Class) this.componentType;
} }
factory.register(type, this); factory.register(type, this);
this.componentDecoder = factory.loadDecoder(this.componentType); this.componentDecoder = factory.loadDecoder(this.componentType);
this.componentArrayFunction = Creator.funcArray(this.componentClass); this.componentArrayFunction = Creator.funcArray(this.componentClass);
} finally { } finally {
inited = true; inited = true;
lock.lock(); lock.lock();
try { try {
condition.signalAll(); condition.signalAll();
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
} }
@Override @Override
public T[] convertFrom(Reader in) { public T[] convertFrom(Reader in) {
return convertFrom(in, null); return convertFrom(in, null);
} }
public T[] convertFrom(Reader in, DeMember member) { public T[] convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1]; byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder); int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1; int contentLength = -1;
if (len == Reader.SIGN_NULL) { if (len == Reader.SIGN_NULL) {
return null; return null;
} }
if (len == Reader.SIGN_NOLENBUTBYTES) { if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder); contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH; len = Reader.SIGN_NOLENGTH;
} }
if (this.componentDecoder == null) { if (this.componentDecoder == null) {
if (!this.inited) { if (!this.inited) {
lock.lock(); lock.lock();
try { try {
condition.await(); condition.await();
} catch (Exception e) { } catch (Exception e) {
// do nothing // do nothing
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
} }
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals); final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final List<T> result = new ArrayList(); final List<T> result = new ArrayList();
boolean first = true; boolean first = true;
if (len == Reader.SIGN_NOLENGTH) { if (len == Reader.SIGN_NOLENGTH) {
int startPosition = in.position(); int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) { while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first); Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) { if (itemReader == null) {
break; break;
} }
result.add(readMemberValue(itemReader, member, localdecoder, first)); result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false; first = false;
} }
} else { } else {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
result.add(localdecoder.convertFrom(in)); result.add(localdecoder.convertFrom(in));
} }
} }
in.readArrayE(); in.readArrayE();
T[] rs = this.componentArrayFunction.apply(result.size()); T[] rs = this.componentArrayFunction.apply(result.size());
return result.toArray(rs); return result.toArray(rs);
} }
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength); return in.hasNext(startPosition, contentLength);
} }
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) { protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder; return decoder;
} }
protected Reader getItemReader(Reader in, DeMember member, boolean first) { protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in; return in;
} }
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) { protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
if (in == null) { if (in == null) {
return null; return null;
} }
return decoder.convertFrom(in); return decoder.convertFrom(in);
} }
@Override @Override
public String toString() { public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:"
+ this.componentDecoder + "}"; + this.componentDecoder + "}";
} }
@Override @Override
public Type getType() { public Type getType() {
return type; return type;
} }
public Type getComponentType() { public Type getComponentType() {
return componentType; return componentType;
} }
public Decodeable<Reader, T> getComponentDecoder() { public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder; return componentDecoder;
} }
} }

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